From c10d92f29b6f56c4623bb6cf4b041c985e0203d6 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 10:16:31 +0300 Subject: [PATCH 01/69] refactor: Modify deps & configurations --- .nycrc.json | 30 ++++++ ava.config.js | 21 ++++ eslint.common.config.js | 205 ++++++++++++++++++++++------------------ eslint.config.js | 4 + package.json | 37 +++----- tsconfig.base.json | 11 +++ tsconfig.build.json | 5 + tsconfig.json | 16 ++++ 8 files changed, 214 insertions(+), 115 deletions(-) create mode 100644 .nycrc.json create mode 100644 ava.config.js create mode 100644 tsconfig.base.json create mode 100644 tsconfig.build.json create mode 100644 tsconfig.json diff --git a/.nycrc.json b/.nycrc.json new file mode 100644 index 00000000..6e7c217f --- /dev/null +++ b/.nycrc.json @@ -0,0 +1,30 @@ +{ + "extends": "@istanbuljs/nyc-config-typescript", + "reporter": ["lcov", "text", "text-summary"], + "include": ["src/**"], + "check-coverage": true, + "statements": 90, + "branches": 90, + "functions": 90, + "lines": 90, + "watermarks": { + "statements": [ + 70, + 90 + ], + "branches": [ + 70, + 90 + ], + "functions": [ + 70, + 90 + ], + "lines": [ + 70, + 90 + ] + }, + "cache": true, + "all": true +} \ No newline at end of file diff --git a/ava.config.js b/ava.config.js new file mode 100644 index 00000000..32b18f7f --- /dev/null +++ b/ava.config.js @@ -0,0 +1,21 @@ +// Calculate nodeArguments based on the Node version +const nodeArguments = [ + "--import=tsx/esm", + "--no-warnings=ExperimentalWarning", +]; + +export default { + "extensions": { + ts: "module", + }, + "files": [ + "test/lib/**/*.ts" + ], + "watchMode": { + "ignoreChanges": [ + "test/tmp/**" + ] + }, + nodeArguments, + "workerThreads": false +}; diff --git a/eslint.common.config.js b/eslint.common.config.js index 07876d52..24daf30b 100644 --- a/eslint.common.config.js +++ b/eslint.common.config.js @@ -1,99 +1,118 @@ -import jsdoc from "eslint-plugin-jsdoc"; -import ava from "eslint-plugin-ava"; -import globals from "globals"; -import js from "@eslint/js"; -import google from "eslint-config-google"; +import eslint from "@eslint/js"; +import tseslint from "typescript-eslint"; +import stylistic from "@stylistic/eslint-plugin"; -export default [{ - ignores: [ // Common ignore patterns across all tooling repos - "**/coverage/", - "test/tmp/", - "test/expected/", - "test/fixtures/", - "**/docs/", - "**/jsdocs/", - ], -}, js.configs.recommended, google, ava.configs["flat/recommended"], { - name: "Common ESLint config used for all tooling repos", +export default tseslint.config( + { + // This block defines ignore patterns globally to all configurations below + // (therefore it can use slightly different patterns, see also the eslint "Flat Config" doc) + ignores: [ + ".github/*", + ".reuse/*", + "coverage/*", - plugins: { - jsdoc, - }, - - languageOptions: { - globals: { - ...globals.node, - }, + // Exclude test files + "test/tmp/*", + "test/fixtures/*", - ecmaVersion: 2023, - sourceType: "module", + // Exclude generated code + "lib/*", + ], }, - - settings: { - jsdoc: { - mode: "jsdoc", - - tagNamePreference: { - return: "returns", - augments: "extends", + // Base configs applying to JS and TS files + eslint.configs.recommended, + stylistic.configs.customize({ + indent: "tab", + quotes: "double", + semi: true, + jsx: false, + arrowParens: true, + braceStyle: "1tbs", + blockSpacing: false, + }), { + // Lint all JS files using the eslint parser + files: ["**/*.js"], + languageOptions: { + ecmaVersion: 2022, + sourceType: "module", + }, + }, { + // Lint all TS files using the typescript-eslint parser + // Also enable all recommended typescript-eslint rules + files: ["src/**/*.ts", "test/**/*.ts", "scripts/**/*.ts"], + extends: [ + ...tseslint.configs.recommendedTypeChecked, + ...tseslint.configs.stylisticTypeChecked, + ], + languageOptions: { + ecmaVersion: 2022, + sourceType: "module", + parser: tseslint.parser, + parserOptions: { + project: true, }, }, - }, - - rules: { - "indent": ["error", "tab"], - "linebreak-style": ["error", "unix"], - - "quotes": ["error", "double", { - allowTemplateLiterals: true, - }], - - "semi": ["error", "always"], - "no-negated-condition": "off", - "require-jsdoc": "off", - "no-mixed-requires": "off", - - "max-len": ["error", { - code: 120, - ignoreUrls: true, - ignoreRegExpLiterals: true, - }], - - "no-implicit-coercion": [2, { - allow: ["!!"], - }], - - "comma-dangle": "off", - "no-tabs": "off", - "no-console": 2, // Disallow console.log() - "no-eval": 2, - // The following rule must be disabled as of ESLint 9. - // It's removed and causes issues when present - // https://eslint.org/docs/latest/rules/valid-jsdoc - "valid-jsdoc": 0, - "jsdoc/check-examples": 0, - "jsdoc/check-param-names": 2, - "jsdoc/check-tag-names": 2, - "jsdoc/check-types": 2, - "jsdoc/no-undefined-types": 0, - "jsdoc/require-description": 0, - "jsdoc/require-description-complete-sentence": 0, - "jsdoc/require-example": 0, - "jsdoc/require-hyphen-before-param-description": 0, - "jsdoc/require-param": 2, - "jsdoc/require-param-description": 0, - "jsdoc/require-param-name": 2, - "jsdoc/require-param-type": 2, - "jsdoc/require-returns": 0, - "jsdoc/require-returns-description": 0, - "jsdoc/require-returns-type": 2, - - "jsdoc/tag-lines": [2, "any", { - startLines: 1, - }], - - "jsdoc/valid-types": 0, - "ava/assertion-arguments": 0, - }, -} -]; + rules: { + // TypeScript specific overwrites + // We must disable the base rule as it can report incorrect errors + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": [ + "error", { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], + }, + }, { + // To be discussed: Type-aware checks might add quite some additional work when writing tests + // and could even require us to export types that we would otherwise not export + files: ["test/**/*.ts"], + rules: { + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-enum-comparison": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-unsafe-unary-minus": "off", + }, + }, { + // Overwrite any rules from the configurations above for both, JS and TS files + rules: { + "linebreak-style": [ + "error", + "unix", + ], + "@stylistic/object-curly-spacing": [ + "error", + "never", + ], + "@stylistic/operator-linebreak": ["error", "after"], + "@stylistic/comma-dangle": ["error", { + functions: "never", + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + enums: "always-multiline", + generics: "always-multiline", + tuples: "always-multiline", + }], + "max-len": [ + "error", + { + code: 120, + ignoreUrls: true, + ignoreRegExpLiterals: true, + }, + ], + "no-implicit-coercion": [ + "error", + {allow: ["!!"]}, + ], + "no-console": "error", + "no-eval": "error", + }, + } +); diff --git a/eslint.config.js b/eslint.config.js index f5873aa9..e87b98da 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -2,4 +2,8 @@ import eslintCommonConfig from "./eslint.common.config.js"; export default [ ...eslintCommonConfig, // Load common ESLint config + { + // Add project-specific ESLint config rules here + // in order to override common config + }, ]; diff --git a/package.json b/package.json index 06998ddd..965bff83 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,10 @@ "npm": ">= 8" }, "scripts": { + "build": "npm run cleanup && tsc -p tsconfig.build.json", + "build-test": "tsc --noEmit -p .", + "build-watch": "npm run cleanup && tsc -w -p tsconfig.build.json", + "cleanup": "rimraf lib coverage", "test": "npm run lint && npm run jsdoc-generate && npm run coverage && npm run depcheck", "test-azure": "npm run coverage-xunit", "lint": "eslint ./", @@ -43,7 +47,8 @@ "unit-verbose": "rimraf test/tmp && cross-env UI5_LOG_LVL=verbose ava --verbose --serial", "unit-watch": "npm run unit -- --watch", "unit-xunit": "rimraf test/tmp && ava --node-arguments=\"--experimental-loader=@istanbuljs/esm-loader-hook\" --tap | tap-xunit --dontUseCommentsAsTestNames=true > test-results.xml", - "unit-inspect": "cross-env UI5_LOG_LVL=verbose ava debug --break", + "unit-debug": "cross-env UI5_LOG_LVL=verbose ava debug", + "unit-update-snapshots": "ava --update-snapshots", "coverage": "rimraf test/tmp && nyc ava --node-arguments=\"--experimental-loader=@istanbuljs/esm-loader-hook\"", "coverage-xunit": "nyc --reporter=text --reporter=text-summary --reporter=cobertura npm run unit-xunit", "jsdoc": "npm run jsdoc-generate && open-cli jsdocs/index.html", @@ -63,21 +68,6 @@ "LICENSES/**", ".reuse/**" ], - "ava": { - "files": [ - "test/lib/**/*.js" - ], - "watchMode": { - "ignoreChanges": [ - "test/tmp/**" - ] - }, - "nodeArguments": [ - "--loader=esmock", - "--no-warnings" - ], - "workerThreads": false - }, "nyc": { "reporter": [ "lcov", @@ -134,17 +124,18 @@ "random-int": "^3.0.0" }, "devDependencies": { - "@eslint/js": "^9.8.0", + "@eslint/js": "^9.9.0", "@istanbuljs/esm-loader-hook": "^0.2.0", + "@istanbuljs/nyc-config-typescript": "^1.0.2", + "@stylistic/eslint-plugin": "^2.6.4", + "@types/node": "^20.11.0", + "@types/sinon": "^17.0.3", "ava": "^6.1.3", "chokidar-cli": "^3.0.0", "cross-env": "^7.0.3", "depcheck": "^1.4.7", "docdash": "^2.0.2", - "eslint": "^9.9.1", - "eslint-config-google": "^0.14.0", - "eslint-plugin-ava": "^15.0.1", - "eslint-plugin-jsdoc": "^50.2.2", + "eslint": "^9.9.0", "esmock": "^2.6.7", "globals": "^15.9.0", "jsdoc": "^4.0.3", @@ -152,6 +143,8 @@ "open-cli": "^8.0.0", "rimraf": "^6.0.1", "sinon": "^18.0.0", - "tap-xunit": "^2.4.1" + "tap-xunit": "^2.4.1", + "tsx": "^4.17.0", + "typescript-eslint": "^8.2.0" } } diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 00000000..d4d68beb --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "outDir": "./lib", + "moduleResolution": "node16", + "module": "node16", + "target": "es2022", + "lib": ["ES2022"], + "strict": true, + "sourceMap": true, + } +} diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 00000000..0aa09f59 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + // For creating a release build, only compile the src dir + "extends": "./tsconfig.base.json", + "include": ["src/**/*"], +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..2f4ae369 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + // This is our configuration for development and linting, + // compared to "tsconfig.build.json" it also includes tests + // and other TypeScript sources in the project + // For this reason however, it should not be used to emit JavaScript (except for linting purposes), + // since the output directory would then contain "src" and "test" directories instead of just the content of "src" + "extends": "./tsconfig.base.json", + "include": [ + "src/**/*", + "test/**/*", + ], + "exclude": [ + "test/tmp/**/*", + "test/fixtures/**/*", + ] +} From 0958a315a5939ed3736206dd07af62475a9ab2dc Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 10:17:55 +0300 Subject: [PATCH 02/69] refactor: Rename lib/ to src/ --- {lib => src}/AbstractReader.js | 0 {lib => src}/AbstractReaderWriter.js | 0 {lib => src}/DuplexCollection.js | 0 {lib => src}/ReaderCollection.js | 0 {lib => src}/ReaderCollectionPrioritized.js | 0 {lib => src}/Resource.js | 0 {lib => src}/ResourceFacade.js | 0 {lib => src}/ResourceTagCollection.js | 0 {lib => src}/WriterCollection.js | 0 {lib => src}/adapters/AbstractAdapter.js | 0 {lib => src}/adapters/FileSystem.js | 0 {lib => src}/adapters/Memory.js | 0 {lib => src}/fsInterface.js | 0 {lib => src}/readers/Filter.js | 0 {lib => src}/readers/Link.js | 0 {lib => src}/resourceFactory.js | 0 {lib => src}/tracing/Trace.js | 0 {lib => src}/tracing/traceSummary.js | 0 18 files changed, 0 insertions(+), 0 deletions(-) rename {lib => src}/AbstractReader.js (100%) rename {lib => src}/AbstractReaderWriter.js (100%) rename {lib => src}/DuplexCollection.js (100%) rename {lib => src}/ReaderCollection.js (100%) rename {lib => src}/ReaderCollectionPrioritized.js (100%) rename {lib => src}/Resource.js (100%) rename {lib => src}/ResourceFacade.js (100%) rename {lib => src}/ResourceTagCollection.js (100%) rename {lib => src}/WriterCollection.js (100%) rename {lib => src}/adapters/AbstractAdapter.js (100%) rename {lib => src}/adapters/FileSystem.js (100%) rename {lib => src}/adapters/Memory.js (100%) rename {lib => src}/fsInterface.js (100%) rename {lib => src}/readers/Filter.js (100%) rename {lib => src}/readers/Link.js (100%) rename {lib => src}/resourceFactory.js (100%) rename {lib => src}/tracing/Trace.js (100%) rename {lib => src}/tracing/traceSummary.js (100%) diff --git a/lib/AbstractReader.js b/src/AbstractReader.js similarity index 100% rename from lib/AbstractReader.js rename to src/AbstractReader.js diff --git a/lib/AbstractReaderWriter.js b/src/AbstractReaderWriter.js similarity index 100% rename from lib/AbstractReaderWriter.js rename to src/AbstractReaderWriter.js diff --git a/lib/DuplexCollection.js b/src/DuplexCollection.js similarity index 100% rename from lib/DuplexCollection.js rename to src/DuplexCollection.js diff --git a/lib/ReaderCollection.js b/src/ReaderCollection.js similarity index 100% rename from lib/ReaderCollection.js rename to src/ReaderCollection.js diff --git a/lib/ReaderCollectionPrioritized.js b/src/ReaderCollectionPrioritized.js similarity index 100% rename from lib/ReaderCollectionPrioritized.js rename to src/ReaderCollectionPrioritized.js diff --git a/lib/Resource.js b/src/Resource.js similarity index 100% rename from lib/Resource.js rename to src/Resource.js diff --git a/lib/ResourceFacade.js b/src/ResourceFacade.js similarity index 100% rename from lib/ResourceFacade.js rename to src/ResourceFacade.js diff --git a/lib/ResourceTagCollection.js b/src/ResourceTagCollection.js similarity index 100% rename from lib/ResourceTagCollection.js rename to src/ResourceTagCollection.js diff --git a/lib/WriterCollection.js b/src/WriterCollection.js similarity index 100% rename from lib/WriterCollection.js rename to src/WriterCollection.js diff --git a/lib/adapters/AbstractAdapter.js b/src/adapters/AbstractAdapter.js similarity index 100% rename from lib/adapters/AbstractAdapter.js rename to src/adapters/AbstractAdapter.js diff --git a/lib/adapters/FileSystem.js b/src/adapters/FileSystem.js similarity index 100% rename from lib/adapters/FileSystem.js rename to src/adapters/FileSystem.js diff --git a/lib/adapters/Memory.js b/src/adapters/Memory.js similarity index 100% rename from lib/adapters/Memory.js rename to src/adapters/Memory.js diff --git a/lib/fsInterface.js b/src/fsInterface.js similarity index 100% rename from lib/fsInterface.js rename to src/fsInterface.js diff --git a/lib/readers/Filter.js b/src/readers/Filter.js similarity index 100% rename from lib/readers/Filter.js rename to src/readers/Filter.js diff --git a/lib/readers/Link.js b/src/readers/Link.js similarity index 100% rename from lib/readers/Link.js rename to src/readers/Link.js diff --git a/lib/resourceFactory.js b/src/resourceFactory.js similarity index 100% rename from lib/resourceFactory.js rename to src/resourceFactory.js diff --git a/lib/tracing/Trace.js b/src/tracing/Trace.js similarity index 100% rename from lib/tracing/Trace.js rename to src/tracing/Trace.js diff --git a/lib/tracing/traceSummary.js b/src/tracing/traceSummary.js similarity index 100% rename from lib/tracing/traceSummary.js rename to src/tracing/traceSummary.js From 6b3b18245871a8b37c33e125f1a7b557fcc4f22b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 10:29:46 +0300 Subject: [PATCH 03/69] refactor: Do files rename to *.ts extensions --- lib/AbstractReader.js | 122 +++++ lib/AbstractReader.js.map | 1 + lib/AbstractReaderWriter.js | 67 +++ lib/AbstractReaderWriter.js.map | 1 + lib/DuplexCollection.js | 77 +++ lib/DuplexCollection.js.map | 1 + lib/ReaderCollection.js | 81 +++ lib/ReaderCollection.js.map | 1 + lib/ReaderCollectionPrioritized.js | 86 ++++ lib/ReaderCollectionPrioritized.js.map | 1 + lib/Resource.js | 463 ++++++++++++++++++ lib/Resource.js.map | 1 + lib/ResourceFacade.js | 240 +++++++++ lib/ResourceFacade.js.map | 1 + lib/ResourceTagCollection.js | 107 ++++ lib/ResourceTagCollection.js.map | 1 + lib/WriterCollection.js | 105 ++++ lib/WriterCollection.js.map | 1 + lib/adapters/AbstractAdapter.js | 280 +++++++++++ lib/adapters/AbstractAdapter.js.map | 1 + lib/adapters/FileSystem.js | 345 +++++++++++++ lib/adapters/FileSystem.js.map | 1 + lib/adapters/Memory.js | 162 ++++++ lib/adapters/Memory.js.map | 1 + lib/fsInterface.js | 90 ++++ lib/fsInterface.js.map | 1 + lib/readers/Filter.js | 71 +++ lib/readers/Filter.js.map | 1 + lib/readers/Link.js | 131 +++++ lib/readers/Link.js.map | 1 + lib/resourceFactory.js | 266 ++++++++++ lib/resourceFactory.js.map | 1 + lib/tracing/Trace.js | 91 ++++ lib/tracing/Trace.js.map | 1 + lib/tracing/traceSummary.js | 113 +++++ lib/tracing/traceSummary.js.map | 1 + src/{AbstractReader.js => AbstractReader.ts} | 0 ...eaderWriter.js => AbstractReaderWriter.ts} | 0 ...uplexCollection.js => DuplexCollection.ts} | 0 ...eaderCollection.js => ReaderCollection.ts} | 0 ...ized.js => ReaderCollectionPrioritized.ts} | 0 src/{Resource.js => Resource.ts} | 0 src/{ResourceFacade.js => ResourceFacade.ts} | 0 ...Collection.js => ResourceTagCollection.ts} | 0 ...riterCollection.js => WriterCollection.ts} | 0 ...{AbstractAdapter.js => AbstractAdapter.ts} | 0 src/adapters/{FileSystem.js => FileSystem.ts} | 0 src/adapters/{Memory.js => Memory.ts} | 0 src/{fsInterface.js => fsInterface.ts} | 0 src/readers/{Filter.js => Filter.ts} | 0 src/readers/{Link.js => Link.ts} | 0 ...{resourceFactory.js => resourceFactory.ts} | 0 src/tracing/{Trace.js => Trace.ts} | 0 .../{traceSummary.js => traceSummary.ts} | 0 .../{AbstractReader.js => AbstractReader.ts} | 0 ...eaderWriter.js => AbstractReaderWriter.ts} | 0 ...uplexCollection.js => DuplexCollection.ts} | 0 ...eaderCollection.js => ReaderCollection.ts} | 0 ...ized.js => ReaderCollectionPrioritized.ts} | 0 test/lib/{Resource.js => Resource.ts} | 0 .../{ResourceFacade.js => ResourceFacade.ts} | 0 ...Collection.js => ResourceTagCollection.ts} | 0 ...riterCollection.js => WriterCollection.ts} | 0 ...{AbstractAdapter.js => AbstractAdapter.ts} | 0 .../adapters/{FileSystem.js => FileSystem.ts} | 0 ...{FileSystem_read.js => FileSystem_read.ts} | 0 ...ileSystem_write.js => FileSystem_write.ts} | 0 ...file.js => FileSystem_write_large_file.ts} | 0 .../{Memory_read.js => Memory_read.ts} | 0 .../{Memory_write.js => Memory_write.ts} | 0 test/lib/{fsInterface.js => fsInterface.ts} | 0 test/lib/{glob.js => glob.ts} | 0 ...{package-exports.js => package-exports.ts} | 0 test/lib/readers/{Filter.js => Filter.ts} | 0 test/lib/readers/{Link.js => Link.ts} | 0 ...{resourceFactory.js => resourceFactory.ts} | 0 test/lib/{resources.js => resources.ts} | 0 .../{traceSummary.js => traceSummary.ts} | 0 78 files changed, 2915 insertions(+) create mode 100644 lib/AbstractReader.js create mode 100644 lib/AbstractReader.js.map create mode 100644 lib/AbstractReaderWriter.js create mode 100644 lib/AbstractReaderWriter.js.map create mode 100644 lib/DuplexCollection.js create mode 100644 lib/DuplexCollection.js.map create mode 100644 lib/ReaderCollection.js create mode 100644 lib/ReaderCollection.js.map create mode 100644 lib/ReaderCollectionPrioritized.js create mode 100644 lib/ReaderCollectionPrioritized.js.map create mode 100644 lib/Resource.js create mode 100644 lib/Resource.js.map create mode 100644 lib/ResourceFacade.js create mode 100644 lib/ResourceFacade.js.map create mode 100644 lib/ResourceTagCollection.js create mode 100644 lib/ResourceTagCollection.js.map create mode 100644 lib/WriterCollection.js create mode 100644 lib/WriterCollection.js.map create mode 100644 lib/adapters/AbstractAdapter.js create mode 100644 lib/adapters/AbstractAdapter.js.map create mode 100644 lib/adapters/FileSystem.js create mode 100644 lib/adapters/FileSystem.js.map create mode 100644 lib/adapters/Memory.js create mode 100644 lib/adapters/Memory.js.map create mode 100644 lib/fsInterface.js create mode 100644 lib/fsInterface.js.map create mode 100644 lib/readers/Filter.js create mode 100644 lib/readers/Filter.js.map create mode 100644 lib/readers/Link.js create mode 100644 lib/readers/Link.js.map create mode 100644 lib/resourceFactory.js create mode 100644 lib/resourceFactory.js.map create mode 100644 lib/tracing/Trace.js create mode 100644 lib/tracing/Trace.js.map create mode 100644 lib/tracing/traceSummary.js create mode 100644 lib/tracing/traceSummary.js.map rename src/{AbstractReader.js => AbstractReader.ts} (100%) rename src/{AbstractReaderWriter.js => AbstractReaderWriter.ts} (100%) rename src/{DuplexCollection.js => DuplexCollection.ts} (100%) rename src/{ReaderCollection.js => ReaderCollection.ts} (100%) rename src/{ReaderCollectionPrioritized.js => ReaderCollectionPrioritized.ts} (100%) rename src/{Resource.js => Resource.ts} (100%) rename src/{ResourceFacade.js => ResourceFacade.ts} (100%) rename src/{ResourceTagCollection.js => ResourceTagCollection.ts} (100%) rename src/{WriterCollection.js => WriterCollection.ts} (100%) rename src/adapters/{AbstractAdapter.js => AbstractAdapter.ts} (100%) rename src/adapters/{FileSystem.js => FileSystem.ts} (100%) rename src/adapters/{Memory.js => Memory.ts} (100%) rename src/{fsInterface.js => fsInterface.ts} (100%) rename src/readers/{Filter.js => Filter.ts} (100%) rename src/readers/{Link.js => Link.ts} (100%) rename src/{resourceFactory.js => resourceFactory.ts} (100%) rename src/tracing/{Trace.js => Trace.ts} (100%) rename src/tracing/{traceSummary.js => traceSummary.ts} (100%) rename test/lib/{AbstractReader.js => AbstractReader.ts} (100%) rename test/lib/{AbstractReaderWriter.js => AbstractReaderWriter.ts} (100%) rename test/lib/{DuplexCollection.js => DuplexCollection.ts} (100%) rename test/lib/{ReaderCollection.js => ReaderCollection.ts} (100%) rename test/lib/{ReaderCollectionPrioritized.js => ReaderCollectionPrioritized.ts} (100%) rename test/lib/{Resource.js => Resource.ts} (100%) rename test/lib/{ResourceFacade.js => ResourceFacade.ts} (100%) rename test/lib/{ResourceTagCollection.js => ResourceTagCollection.ts} (100%) rename test/lib/{WriterCollection.js => WriterCollection.ts} (100%) rename test/lib/adapters/{AbstractAdapter.js => AbstractAdapter.ts} (100%) rename test/lib/adapters/{FileSystem.js => FileSystem.ts} (100%) rename test/lib/adapters/{FileSystem_read.js => FileSystem_read.ts} (100%) rename test/lib/adapters/{FileSystem_write.js => FileSystem_write.ts} (100%) rename test/lib/adapters/{FileSystem_write_large_file.js => FileSystem_write_large_file.ts} (100%) rename test/lib/adapters/{Memory_read.js => Memory_read.ts} (100%) rename test/lib/adapters/{Memory_write.js => Memory_write.ts} (100%) rename test/lib/{fsInterface.js => fsInterface.ts} (100%) rename test/lib/{glob.js => glob.ts} (100%) rename test/lib/{package-exports.js => package-exports.ts} (100%) rename test/lib/readers/{Filter.js => Filter.ts} (100%) rename test/lib/readers/{Link.js => Link.ts} (100%) rename test/lib/{resourceFactory.js => resourceFactory.ts} (100%) rename test/lib/{resources.js => resources.ts} (100%) rename test/lib/tracing/{traceSummary.js => traceSummary.ts} (100%) diff --git a/lib/AbstractReader.js b/lib/AbstractReader.js new file mode 100644 index 00000000..e941c375 --- /dev/null +++ b/lib/AbstractReader.js @@ -0,0 +1,122 @@ +import randomInt from "random-int"; +import Trace from "./tracing/Trace.js"; +/** + * Abstract resource locator implementing the general API for reading resources + * + * @abstract + * @public + * @class + * @alias @ui5/fs/AbstractReader + */ +class AbstractReader { + /** + * The constructor. + * + * @public + * @param {string} name Name of the reader. Typically used for tracing purposes + */ + constructor(name) { + if (new.target === AbstractReader) { + throw new TypeError("Class 'AbstractReader' is abstract"); + } + this._name = name; + } + /* + * Returns the name of the reader instance. This can be used for logging/tracing purposes. + * + * @returns {string} Name of the reader + */ + getName() { + return this._name || ``; + } + /** + * Locates resources by matching glob patterns. + * + * @example + * byGlob("**‏/*.{html,htm}"); + * byGlob("**‏/.library"); + * byGlob("/pony/*"); + * + * @public + * @param {string|string[]} virPattern glob pattern as string or array of glob patterns for + * virtual directory structure + * @param {object} [options] glob options + * @param {boolean} [options.nodir=true] Do not match directories + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + */ + byGlob(virPattern, options = { nodir: true }) { + const trace = new Trace(virPattern); + return this._byGlob(virPattern, options, trace).then(function (result) { + trace.printReport(); + return result; + }).then((resources) => { + if (resources.length > 1) { + // Pseudo randomize result order to prevent consumers from relying on it: + // Swap the first object with a randomly chosen one + const x = 0; + const y = randomInt(0, resources.length - 1); + // Swap object at index "x" with "y" + resources[x] = [resources[y], resources[y] = resources[x]][0]; + } + return resources; + }); + } + /** + * Locates resources by matching a given path. + * + * @public + * @param {string} virPath Virtual path + * @param {object} [options] Options + * @param {boolean} [options.nodir=true] Do not match directories + * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + */ + byPath(virPath, options = { nodir: true }) { + const trace = new Trace(virPath); + return this._byPath(virPath, options, trace).then(function (resource) { + trace.printReport(); + return resource; + }); + } + /** + * Locates resources by one or more glob patterns. + * + * @abstract + * @protected + * @param {string|string[]} virPattern glob pattern as string or an array of + * glob patterns for virtual directory structure + * @param {object} options glob options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + */ + _byGlob(virPattern, options, trace) { + throw new Error("Function '_byGlob' is not implemented"); + } + /** + * Locate resources by matching a single glob pattern. + * + * @abstract + * @protected + * @param {string} pattern glob pattern + * @param {object} options glob options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + */ + _runGlob(pattern, options, trace) { + throw new Error("Function '_runGlob' is not implemented"); + } + /** + * Locates resources by path. + * + * @abstract + * @protected + * @param {string} virPath Virtual path + * @param {object} options Options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + */ + _byPath(virPath, options, trace) { + throw new Error("Function '_byPath' is not implemented"); + } +} +export default AbstractReader; +//# sourceMappingURL=AbstractReader.js.map \ No newline at end of file diff --git a/lib/AbstractReader.js.map b/lib/AbstractReader.js.map new file mode 100644 index 00000000..7fe74331 --- /dev/null +++ b/lib/AbstractReader.js.map @@ -0,0 +1 @@ +{"version":3,"file":"AbstractReader.js","sourceRoot":"","sources":["../src/AbstractReader.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,MAAM,oBAAoB,CAAC;AAEvC;;;;;;;GAOG;AACH,MAAM,cAAc;IACnB;;;;;OAKG;IACH,YAAY,IAAI;QACf,IAAI,GAAG,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;YACnC,MAAM,IAAI,SAAS,CAAC,oCAAoC,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,OAAO;QACN,OAAO,IAAI,CAAC,KAAK,IAAI,YAAY,IAAI,CAAC,WAAW,CAAC,IAAI,UAAU,CAAC;IAClE,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,UAAU,EAAE,OAAO,GAAG,EAAC,KAAK,EAAE,IAAI,EAAC;QACzC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,UAAS,MAAM;YACnE,KAAK,CAAC,WAAW,EAAE,CAAC;YACpB,OAAO,MAAM,CAAC;QACf,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;YACrB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,yEAAyE;gBACzE,mDAAmD;gBACnD,MAAM,CAAC,GAAG,CAAC,CAAC;gBACZ,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAC7C,qCAAqC;gBACrC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,GAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7D,CAAC;YACD,OAAO,SAAS,CAAC;QAClB,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,EAAC,KAAK,EAAE,IAAI,EAAC;QACtC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,UAAS,QAAQ;YAClE,KAAK,CAAC,WAAW,EAAE,CAAC;YACpB,OAAO,QAAQ,CAAC;QACjB,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;;;OAUG;IACH,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK;QACjC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC1D,CAAC;IAED;;;;;;;;;OASG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC/B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC3D,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC1D,CAAC;CACD;AAED,eAAe,cAAc,CAAC"} \ No newline at end of file diff --git a/lib/AbstractReaderWriter.js b/lib/AbstractReaderWriter.js new file mode 100644 index 00000000..720ae73d --- /dev/null +++ b/lib/AbstractReaderWriter.js @@ -0,0 +1,67 @@ +import AbstractReader from "./AbstractReader.js"; +/** + * Abstract resource locator implementing the general API for reading and writing resources + * + * @abstract + * @public + * @class + * @alias @ui5/fs/AbstractReaderWriter + * @extends @ui5/fs/AbstractReader + */ +class AbstractReaderWriter extends AbstractReader { + /** + * The constructor. + * + * @public + * @param {string} name Name of the reader/writer. Typically used for tracing purposes + */ + constructor(name) { + if (new.target === AbstractReaderWriter) { + throw new TypeError("Class 'AbstractReaderWriter' is abstract"); + } + super(name); + } + /* + * Returns the name of the reader/writer instance. This can be used for logging/tracing purposes. + * + * @returns {string} Name of the reader/writer + */ + getName() { + return this._name || ``; + } + /** + * Writes the content of a resource to a path. + * + * @public + * @param {@ui5/fs/Resource} resource Resource to write + * @param {object} [options] + * @param {boolean} [options.readOnly=false] Whether the resource content shall be written read-only + * Do not use in conjunction with the drain option. + * The written file will be used as the new source of this resources content. + * Therefore the written file should not be altered by any means. + * Activating this option might improve overall memory consumption. + * @param {boolean} [options.drain=false] Whether the resource content shall be emptied during the write process. + * Do not use in conjunction with the readOnly option. + * Activating this option might improve overall memory consumption. + * This should be used in cases where this is the last access to the resource. + * E.g. the final write of a resource after all processing is finished. + * @returns {Promise} Promise resolving once data has been written + */ + write(resource, options = { drain: false, readOnly: false }) { + return this._write(resource, options); + } + /** + * Writes the content of a resource to a path. + * + * @abstract + * @protected + * @param {@ui5/fs/Resource} resource Resource to write + * @param {object} [options] Write options, see above + * @returns {Promise} Promise resolving once data has been written + */ + _write(resource, options) { + throw new Error("Not implemented"); + } +} +export default AbstractReaderWriter; +//# sourceMappingURL=AbstractReaderWriter.js.map \ No newline at end of file diff --git a/lib/AbstractReaderWriter.js.map b/lib/AbstractReaderWriter.js.map new file mode 100644 index 00000000..d9adb158 --- /dev/null +++ b/lib/AbstractReaderWriter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"AbstractReaderWriter.js","sourceRoot":"","sources":["../src/AbstractReaderWriter.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,oBAAqB,SAAQ,cAAc;IAChD;;;;;OAKG;IACH,YAAY,IAAI;QACf,IAAI,GAAG,CAAC,MAAM,KAAK,oBAAoB,EAAE,CAAC;YACzC,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;QACjE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,CAAC;IACb,CAAC;IAED;;;;OAIG;IACH,OAAO;QACN,OAAO,IAAI,CAAC,KAAK,IAAI,YAAY,IAAI,CAAC,WAAW,CAAC,IAAI,iBAAiB,CAAC;IACzE,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,QAAQ,EAAE,OAAO,GAAG,EAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAC;QACxD,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,QAAQ,EAAE,OAAO;QACvB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACpC,CAAC;CACD;AAED,eAAe,oBAAoB,CAAC"} \ No newline at end of file diff --git a/lib/DuplexCollection.js b/lib/DuplexCollection.js new file mode 100644 index 00000000..5a167354 --- /dev/null +++ b/lib/DuplexCollection.js @@ -0,0 +1,77 @@ +import AbstractReaderWriter from "./AbstractReaderWriter.js"; +import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; +/** + * Wrapper to keep readers and writers together + * + * @public + * @class + * @alias @ui5/fs/DuplexCollection + * @extends @ui5/fs/AbstractReaderWriter + */ +class DuplexCollection extends AbstractReaderWriter { + /** + * The Constructor. + * + * @param {object} parameters + * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers + * @param {@ui5/fs/AbstractReaderWriter} parameters.writer + * A ReaderWriter instance which is only used for writing files + * @param {string} [parameters.name=""] The collection name + */ + constructor({ reader, writer, name = "" }) { + super(name); + if (!reader) { + throw new Error(`Cannot create DuplexCollection ${this._name}: No reader provided`); + } + if (!writer) { + throw new Error(`Cannot create DuplexCollection ${this._name}: No writer provided`); + } + this._reader = reader; + this._writer = writer; + this._combo = new ReaderCollectionPrioritized({ + name: `${name} - ReaderCollectionPrioritized`, + readers: [ + writer, + reader + ] + }); + } + /** + * Locates resources by glob. + * + * @private + * @param {string|string[]} virPattern glob pattern as string or an array of + * glob patterns for virtual directory structure + * @param {object} options glob options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving with a list of resources + */ + _byGlob(virPattern, options, trace) { + return this._combo._byGlob(virPattern, options, trace); + } + /** + * Locates resources by path. + * + * @private + * @param {string} virPath Virtual path + * @param {object} options Options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource|null>} + * Promise resolving to a single resource or null if no resource is found + */ + _byPath(virPath, options, trace) { + return this._combo._byPath(virPath, options, trace); + } + /** + * Writes the content of a resource to a path. + * + * @private + * @param {@ui5/fs/Resource} resource The Resource to write + * @returns {Promise} Promise resolving once data has been written + */ + _write(resource) { + return this._writer.write(resource); + } +} +export default DuplexCollection; +//# sourceMappingURL=DuplexCollection.js.map \ No newline at end of file diff --git a/lib/DuplexCollection.js.map b/lib/DuplexCollection.js.map new file mode 100644 index 00000000..9f7fad5f --- /dev/null +++ b/lib/DuplexCollection.js.map @@ -0,0 +1 @@ +{"version":3,"file":"DuplexCollection.js","sourceRoot":"","sources":["../src/DuplexCollection.ts"],"names":[],"mappings":"AAAA,OAAO,oBAAoB,MAAM,2BAA2B,CAAC;AAC7D,OAAO,2BAA2B,MAAM,kCAAkC,CAAC;AAE3E;;;;;;;GAOG;AACH,MAAM,gBAAiB,SAAQ,oBAAoB;IAClD;;;;;;;;OAQG;IACH,YAAY,EAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE,EAAC;QACtC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEZ,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,CAAC,KAAK,sBAAsB,CAAC,CAAC;QACrF,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,CAAC,KAAK,sBAAsB,CAAC,CAAC;QACrF,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QAEtB,IAAI,CAAC,MAAM,GAAG,IAAI,2BAA2B,CAAC;YAC7C,IAAI,EAAE,GAAG,IAAI,gCAAgC;YAC7C,OAAO,EAAE;gBACR,MAAM;gBACN,MAAM;aACN;SACD,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK;QACjC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;CACD;AAED,eAAe,gBAAgB,CAAC"} \ No newline at end of file diff --git a/lib/ReaderCollection.js b/lib/ReaderCollection.js new file mode 100644 index 00000000..4e644783 --- /dev/null +++ b/lib/ReaderCollection.js @@ -0,0 +1,81 @@ +import AbstractReader from "./AbstractReader.js"; +/** + * Resource Locator ReaderCollection + * + * @public + * @class + * @alias @ui5/fs/ReaderCollection + * @extends @ui5/fs/AbstractReader + */ +class ReaderCollection extends AbstractReader { + /** + * The constructor. + * + * @param {object} parameters Parameters + * @param {string} parameters.name The collection name + * @param {@ui5/fs/AbstractReader[]} [parameters.readers] + * List of resource readers (all tried in parallel). + * If none are provided, the collection will never return any results. + */ + constructor({ name, readers }) { + super(name); + // Remove any undefined (empty) readers from array + this._readers = readers.filter(($) => $); + } + /** + * Locates resources by glob. + * + * @private + * @param {string|string[]} pattern glob pattern as string or an array of + * glob patterns for virtual directory structure + * @param {object} options glob options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + */ + _byGlob(pattern, options, trace) { + return Promise.all(this._readers.map(function (resourceLocator) { + return resourceLocator._byGlob(pattern, options, trace); + })).then((result) => { + trace.collection(this._name); + return Array.prototype.concat.apply([], result); + }); + } + /** + * Locates resources by path. + * + * @private + * @param {string} virPath Virtual path + * @param {object} options Options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource|null>} + * Promise resolving to a single resource or null if no resource is found + */ + _byPath(virPath, options, trace) { + const that = this; + const resourceLocatorCount = this._readers.length; + let resolveCount = 0; + if (resourceLocatorCount === 0) { + // Short-circuit if there are no readers (Promise.race does not settle for empty arrays) + trace.collection(that._name); + return Promise.resolve(null); + } + // Using Promise.race to deliver files that can be found as fast as possible + return Promise.race(this._readers.map(function (resourceLocator) { + return resourceLocator._byPath(virPath, options, trace).then(function (resource) { + return new Promise(function (resolve, reject) { + trace.collection(that._name); + resolveCount++; + if (resource) { + resource.pushCollection(that._name); + resolve(resource); + } + else if (resolveCount === resourceLocatorCount) { + resolve(null); + } + }); + }); + })); + } +} +export default ReaderCollection; +//# sourceMappingURL=ReaderCollection.js.map \ No newline at end of file diff --git a/lib/ReaderCollection.js.map b/lib/ReaderCollection.js.map new file mode 100644 index 00000000..563f6264 --- /dev/null +++ b/lib/ReaderCollection.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ReaderCollection.js","sourceRoot":"","sources":["../src/ReaderCollection.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,gBAAiB,SAAQ,cAAc;IAC5C;;;;;;;;OAQG;IACH,YAAY,EAAC,IAAI,EAAE,OAAO,EAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,CAAC;QAEZ,kDAAkD;QAClD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAS,eAAe;YAC5D,OAAO,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACnB,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,OAAO,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,MAAM,oBAAoB,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAClD,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,IAAI,oBAAoB,KAAK,CAAC,EAAE,CAAC;YAChC,wFAAwF;YACxF,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;QAED,4EAA4E;QAC5E,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAS,eAAe;YAC7D,OAAO,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,UAAS,QAAQ;gBAC7E,OAAO,IAAI,OAAO,CAAC,UAAS,OAAO,EAAE,MAAM;oBAC1C,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAC7B,YAAY,EAAE,CAAC;oBACf,IAAI,QAAQ,EAAE,CAAC;wBACd,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;wBACpC,OAAO,CAAC,QAAQ,CAAC,CAAC;oBACnB,CAAC;yBAAM,IAAI,YAAY,KAAK,oBAAoB,EAAE,CAAC;wBAClD,OAAO,CAAC,IAAI,CAAC,CAAC;oBACf,CAAC;gBACF,CAAC,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC,CAAC;IACL,CAAC;CACD;AAED,eAAe,gBAAgB,CAAC"} \ No newline at end of file diff --git a/lib/ReaderCollectionPrioritized.js b/lib/ReaderCollectionPrioritized.js new file mode 100644 index 00000000..993a372c --- /dev/null +++ b/lib/ReaderCollectionPrioritized.js @@ -0,0 +1,86 @@ +import AbstractReader from "./AbstractReader.js"; +/** + * Prioritized Resource Locator Collection + * + * @public + * @class + * @alias @ui5/fs/ReaderCollectionPrioritized + * @extends @ui5/fs/AbstractReader + */ +class ReaderCollectionPrioritized extends AbstractReader { + /** + * The constructor. + * + * @param {object} parameters + * @param {string} parameters.name The collection name + * @param {@ui5/fs/AbstractReader[]} [parameters.readers] + * Prioritized list of resource readers (tried in the order provided). + * If none are provided, the collection will never return any results. + */ + constructor({ readers, name }) { + super(name); + // Remove any undefined (empty) readers from array + this._readers = readers.filter(($) => $); + } + /** + * Locates resources by glob. + * + * @private + * @param {string|string[]} pattern glob pattern as string or an array of + * glob patterns for virtual directory structure + * @param {object} options glob options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + */ + _byGlob(pattern, options, trace) { + return Promise.all(this._readers.map(function (resourceLocator) { + return resourceLocator._byGlob(pattern, options, trace); + })).then((result) => { + const files = Object.create(null); + const resources = []; + // Prefer files found in preceding resource locators + for (let i = 0; i < result.length; i++) { + for (let j = 0; j < result[i].length; j++) { + const resource = result[i][j]; + const path = resource.getPath(); + if (!files[path]) { + files[path] = true; + resources.push(resource); + } + } + } + trace.collection(this._name); + return resources; + }); + } + /** + * Locates resources by path. + * + * @private + * @param {string} virPath Virtual path + * @param {object} options Options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource|null>} + * Promise resolving to a single resource or null if no resource is found + */ + _byPath(virPath, options, trace) { + const that = this; + const byPath = (i) => { + if (i > this._readers.length - 1) { + return null; + } + return this._readers[i]._byPath(virPath, options, trace).then((resource) => { + if (resource) { + resource.pushCollection(that._name); + return resource; + } + else { + return byPath(++i); + } + }); + }; + return byPath(0); + } +} +export default ReaderCollectionPrioritized; +//# sourceMappingURL=ReaderCollectionPrioritized.js.map \ No newline at end of file diff --git a/lib/ReaderCollectionPrioritized.js.map b/lib/ReaderCollectionPrioritized.js.map new file mode 100644 index 00000000..d3a68304 --- /dev/null +++ b/lib/ReaderCollectionPrioritized.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ReaderCollectionPrioritized.js","sourceRoot":"","sources":["../src/ReaderCollectionPrioritized.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,2BAA4B,SAAQ,cAAc;IACvD;;;;;;;;OAQG;IACH,YAAY,EAAC,OAAO,EAAE,IAAI,EAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,CAAC;QAEZ,kDAAkD;QAClD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAS,eAAe;YAC5D,OAAO,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACnB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,SAAS,GAAG,EAAE,CAAC;YACrB,oDAAoD;YACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC3C,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;oBAChC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;wBAClB,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;wBACnB,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC1B,CAAC;gBACF,CAAC;YACF,CAAC;YAED,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,OAAO,SAAS,CAAC;QAClB,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE;YACpB,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,OAAO,IAAI,CAAC;YACb,CAAC;YACD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;gBAC1E,IAAI,QAAQ,EAAE,CAAC;oBACd,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACpC,OAAO,QAAQ,CAAC;gBACjB,CAAC;qBAAM,CAAC;oBACP,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;gBACpB,CAAC;YACF,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC;QACF,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;CACD;AAED,eAAe,2BAA2B,CAAC"} \ No newline at end of file diff --git a/lib/Resource.js b/lib/Resource.js new file mode 100644 index 00000000..c7616041 --- /dev/null +++ b/lib/Resource.js @@ -0,0 +1,463 @@ +import stream from "node:stream"; +import clone from "clone"; +import posixPath from "node:path/posix"; +const fnTrue = () => true; +const fnFalse = () => false; +const ALLOWED_SOURCE_METADATA_KEYS = ["adapter", "fsPath", "contentModified"]; +/** + * Resource. UI5 Tooling specific representation of a file's content and metadata + * + * @public + * @class + * @alias @ui5/fs/Resource + */ +class Resource { + #project; + #buffer; + #buffering; + #collections; + #contentDrained; + #createStream; + #name; + #path; + #sourceMetadata; + #statInfo; + #stream; + #streamDrained; + #isModified; + /** + * Function for dynamic creation of content streams + * + * @public + * @callback @ui5/fs/Resource~createStream + * @returns {stream.Readable} A readable stream of a resources content + */ + /** + * + * @public + * @param {object} parameters Parameters + * @param {string} parameters.path Absolute virtual path of the resource + * @param {fs.Stats|object} [parameters.statInfo] File information. Instance of + * [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} or similar object + * @param {Buffer} [parameters.buffer] Content of this resources as a Buffer instance + * (cannot be used in conjunction with parameters string, stream or createStream) + * @param {string} [parameters.string] Content of this resources as a string + * (cannot be used in conjunction with parameters buffer, stream or createStream) + * @param {Stream} [parameters.stream] Readable stream of the content of this resource + * (cannot be used in conjunction with parameters buffer, string or createStream) + * @param {@ui5/fs/Resource~createStream} [parameters.createStream] Function callback that returns a readable + * stream of the content of this resource (cannot be used in conjunction with parameters buffer, + * string or stream). + * In some cases this is the most memory-efficient way to supply resource content + * @param {@ui5/project/specifications/Project} [parameters.project] Project this resource is associated with + * @param {object} [parameters.sourceMetadata] Source metadata for UI5 Tooling internal use. + * Some information may be set by an adapter to store information for later retrieval. Also keeps track of whether + * a resource content has been modified since it has been read from a source + */ + constructor({ path, statInfo, buffer, string, createStream, stream, project, sourceMetadata }) { + if (!path) { + throw new Error("Unable to create Resource: Missing parameter 'path'"); + } + if (buffer && createStream || buffer && string || string && createStream || buffer && stream || + string && stream || createStream && stream) { + throw new Error("Unable to create Resource: Please set only one content parameter. " + + "'buffer', 'string', 'stream' or 'createStream'"); + } + if (sourceMetadata) { + if (typeof sourceMetadata !== "object") { + throw new Error(`Parameter 'sourceMetadata' must be of type "object"`); + } + /* eslint-disable-next-line guard-for-in */ + for (const metadataKey in sourceMetadata) { // Also check prototype + if (!ALLOWED_SOURCE_METADATA_KEYS.includes(metadataKey)) { + throw new Error(`Parameter 'sourceMetadata' contains an illegal attribute: ${metadataKey}`); + } + if (!["string", "boolean"].includes(typeof sourceMetadata[metadataKey])) { + throw new Error(`Attribute '${metadataKey}' of parameter 'sourceMetadata' ` + + `must be of type "string" or "boolean"`); + } + } + } + this.setPath(path); + this.#sourceMetadata = sourceMetadata || {}; + // This flag indicates whether a resource has changed from its original source. + // resource.isModified() is not sufficient, since it only reflects the modification state of the + // current instance. + // Since the sourceMetadata object is inherited to clones, it is the only correct indicator + this.#sourceMetadata.contentModified ??= false; + this.#isModified = false; + this.#project = project; + this.#statInfo = statInfo || { + isFile: fnTrue, + isDirectory: fnFalse, + isBlockDevice: fnFalse, + isCharacterDevice: fnFalse, + isSymbolicLink: fnFalse, + isFIFO: fnFalse, + isSocket: fnFalse, + atimeMs: new Date().getTime(), + mtimeMs: new Date().getTime(), + ctimeMs: new Date().getTime(), + birthtimeMs: new Date().getTime(), + atime: new Date(), + mtime: new Date(), + ctime: new Date(), + birthtime: new Date() + }; + if (createStream) { + this.#createStream = createStream; + } + else if (stream) { + this.#stream = stream; + } + else if (buffer) { + // Use private setter, not to accidentally set any modified flags + this.#setBuffer(buffer); + } + else if (typeof string === "string" || string instanceof String) { + // Use private setter, not to accidentally set any modified flags + this.#setBuffer(Buffer.from(string, "utf8")); + } + // Tracing: + this.#collections = []; + } + /** + * Gets a buffer with the resource content. + * + * @public + * @returns {Promise} Promise resolving with a buffer of the resource content. + */ + async getBuffer() { + if (this.#contentDrained) { + throw new Error(`Content of Resource ${this.#path} has been drained. ` + + "This might be caused by requesting resource content after a content stream has been " + + "requested and no new content (e.g. a new stream) has been set."); + } + if (this.#buffer) { + return this.#buffer; + } + else if (this.#createStream || this.#stream) { + return this.#getBufferFromStream(); + } + else { + throw new Error(`Resource ${this.#path} has no content`); + } + } + /** + * Sets a Buffer as content. + * + * @public + * @param {Buffer} buffer Buffer instance + */ + setBuffer(buffer) { + this.#sourceMetadata.contentModified = true; + this.#isModified = true; + this.#setBuffer(buffer); + } + #setBuffer(buffer) { + this.#createStream = null; + // if (this.#stream) { // TODO this may cause strange issues + // this.#stream.destroy(); + // } + this.#stream = null; + this.#buffer = buffer; + this.#contentDrained = false; + this.#streamDrained = false; + } + /** + * Gets a string with the resource content. + * + * @public + * @returns {Promise} Promise resolving with the resource content. + */ + getString() { + if (this.#contentDrained) { + return Promise.reject(new Error(`Content of Resource ${this.#path} has been drained. ` + + "This might be caused by requesting resource content after a content stream has been " + + "requested and no new content (e.g. a new stream) has been set.")); + } + return this.getBuffer().then((buffer) => buffer.toString()); + } + /** + * Sets a String as content + * + * @public + * @param {string} string Resource content + */ + setString(string) { + this.setBuffer(Buffer.from(string, "utf8")); + } + /** + * Gets a readable stream for the resource content. + * + * Repetitive calls of this function are only possible if new content has been set in the meantime (through + * [setStream]{@link @ui5/fs/Resource#setStream}, [setBuffer]{@link @ui5/fs/Resource#setBuffer} + * or [setString]{@link @ui5/fs/Resource#setString}). This + * is to prevent consumers from accessing drained streams. + * + * @public + * @returns {stream.Readable} Readable stream for the resource content. + */ + getStream() { + if (this.#contentDrained) { + throw new Error(`Content of Resource ${this.#path} has been drained. ` + + "This might be caused by requesting resource content after a content stream has been " + + "requested and no new content (e.g. a new stream) has been set."); + } + let contentStream; + if (this.#buffer) { + const bufferStream = new stream.PassThrough(); + bufferStream.end(this.#buffer); + contentStream = bufferStream; + } + else if (this.#createStream || this.#stream) { + contentStream = this.#getStream(); + } + if (!contentStream) { + throw new Error(`Resource ${this.#path} has no content`); + } + // If a stream instance is being returned, it will typically get drained be the consumer. + // In that case, further content access will result in a "Content stream has been drained" error. + // However, depending on the execution environment, a resources content stream might have been + // transformed into a buffer. In that case further content access is possible as a buffer can't be + // drained. + // To prevent unexpected "Content stream has been drained" errors caused by changing environments, we flag + // the resource content as "drained" every time a stream is requested. Even if actually a buffer or + // createStream callback is being used. + this.#contentDrained = true; + return contentStream; + } + /** + * Sets a readable stream as content. + * + * @public + * @param {stream.Readable|@ui5/fs/Resource~createStream} stream Readable stream of the resource content or + callback for dynamic creation of a readable stream + */ + setStream(stream) { + this.#isModified = true; + this.#sourceMetadata.contentModified = true; + this.#buffer = null; + // if (this.#stream) { // TODO this may cause strange issues + // this.#stream.destroy(); + // } + if (typeof stream === "function") { + this.#createStream = stream; + this.#stream = null; + } + else { + this.#stream = stream; + this.#createStream = null; + } + this.#contentDrained = false; + this.#streamDrained = false; + } + /** + * Gets the virtual resources path + * + * @public + * @returns {string} Virtual path of the resource + */ + getPath() { + return this.#path; + } + /** + * Sets the virtual resources path + * + * @public + * @param {string} path Absolute virtual path of the resource + */ + setPath(path) { + path = posixPath.normalize(path); + if (!posixPath.isAbsolute(path)) { + throw new Error(`Unable to set resource path: Path must be absolute: ${path}`); + } + this.#path = path; + this.#name = posixPath.basename(path); + } + /** + * Gets the resource name + * + * @public + * @returns {string} Name of the resource + */ + getName() { + return this.#name; + } + /** + * Gets the resources stat info. + * Note that a resources stat information is not updated when the resource is being modified. + * Also, depending on the used adapter, some fields might be missing which would be present for a + * [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} instance. + * + * @public + * @returns {fs.Stats|object} Instance of [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} + * or similar object + */ + getStatInfo() { + return this.#statInfo; + } + /** + * Size in bytes allocated by the underlying buffer. + * + * @see {TypedArray#byteLength} + * @returns {Promise} size in bytes, 0 if there is no content yet + */ + async getSize() { + // if resource does not have any content it should have 0 bytes + if (!this.#buffer && !this.#createStream && !this.#stream) { + return 0; + } + const buffer = await this.getBuffer(); + return buffer.byteLength; + } + /** + * Adds a resource collection name that was involved in locating this resource. + * + * @param {string} name Resource collection name + */ + pushCollection(name) { + this.#collections.push(name); + } + /** + * Returns a clone of the resource. The clones content is independent from that of the original resource + * + * @public + * @returns {Promise<@ui5/fs/Resource>} Promise resolving with the clone + */ + async clone() { + const options = await this.#getCloneOptions(); + return new Resource(options); + } + async #getCloneOptions() { + const options = { + path: this.#path, + statInfo: clone(this.#statInfo), + sourceMetadata: clone(this.#sourceMetadata) + }; + if (this.#stream) { + options.buffer = await this.#getBufferFromStream(); + } + else if (this.#createStream) { + options.createStream = this.#createStream; + } + else if (this.#buffer) { + options.buffer = this.#buffer; + } + return options; + } + /** + * Retrieve the project assigned to the resource + *
+ * Note for UI5 Tooling extensions (i.e. custom tasks, custom middleware): + * In order to ensure compatibility across UI5 Tooling versions, consider using the + * getProject(resource) method provided by + * [TaskUtil]{@link module:@ui5/project/build/helpers/TaskUtil} and + * [MiddlewareUtil]{@link module:@ui5/server.middleware.MiddlewareUtil}, which will + * return a Specification Version-compatible Project interface. + * + * @public + * @returns {@ui5/project/specifications/Project} Project this resource is associated with + */ + getProject() { + return this.#project; + } + /** + * Assign a project to the resource + * + * @public + * @param {@ui5/project/specifications/Project} project Project this resource is associated with + */ + setProject(project) { + if (this.#project) { + throw new Error(`Unable to assign project ${project.getName()} to resource ${this.#path}: ` + + `Resource is already associated to project ${this.#project}`); + } + this.#project = project; + } + /** + * Check whether a project has been assigned to the resource + * + * @public + * @returns {boolean} True if the resource is associated with a project + */ + hasProject() { + return !!this.#project; + } + /** + * Check whether the content of this resource has been changed during its life cycle + * + * @public + * @returns {boolean} True if the resource's content has been changed + */ + isModified() { + return this.#isModified; + } + /** + * Tracing: Get tree for printing out trace + * + * @returns {object} Trace tree + */ + getPathTree() { + const tree = Object.create(null); + let pointer = tree[this.#path] = Object.create(null); + for (let i = this.#collections.length - 1; i >= 0; i--) { + pointer = pointer[this.#collections[i]] = Object.create(null); + } + return tree; + } + /** + * Returns source metadata which may contain information specific to the adapter that created the resource + * Typically set by an adapter to store information for later retrieval. + * + * @returns {object} + */ + getSourceMetadata() { + return this.#sourceMetadata; + } + /** + * Returns the content as stream. + * + * @private + * @returns {stream.Readable} Readable stream + */ + #getStream() { + if (this.#streamDrained) { + throw new Error(`Content stream of Resource ${this.#path} is flagged as drained.`); + } + if (this.#createStream) { + return this.#createStream(); + } + this.#streamDrained = true; + return this.#stream; + } + /** + * Converts the buffer into a stream. + * + * @private + * @returns {Promise} Promise resolving with buffer. + */ + #getBufferFromStream() { + if (this.#buffering) { // Prevent simultaneous buffering, causing unexpected access to drained stream + return this.#buffering; + } + return this.#buffering = new Promise((resolve, reject) => { + const contentStream = this.#getStream(); + const buffers = []; + contentStream.on("data", (data) => { + buffers.push(data); + }); + contentStream.on("error", (err) => { + reject(err); + }); + contentStream.on("end", () => { + const buffer = Buffer.concat(buffers); + this.#setBuffer(buffer); + this.#buffering = null; + resolve(buffer); + }); + }); + } +} +export default Resource; +//# sourceMappingURL=Resource.js.map \ No newline at end of file diff --git a/lib/Resource.js.map b/lib/Resource.js.map new file mode 100644 index 00000000..f366b268 --- /dev/null +++ b/lib/Resource.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Resource.js","sourceRoot":"","sources":["../src/Resource.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/ResourceFacade.js b/lib/ResourceFacade.js new file mode 100644 index 00000000..886551ff --- /dev/null +++ b/lib/ResourceFacade.js @@ -0,0 +1,240 @@ +import posixPath from "node:path/posix"; +/** + * A {@link @ui5/fs/Resource Resource} with a different path than it's original + * + * @public + * @class + * @alias @ui5/fs/ResourceFacade + */ +class ResourceFacade { + #path; + #name; + #resource; + /** + * + * @public + * @param {object} parameters Parameters + * @param {string} parameters.path Virtual path of the facade resource + * @param {@ui5/fs/Resource} parameters.resource Resource to conceal + */ + constructor({ path, resource }) { + if (!path) { + throw new Error("Unable to create ResourceFacade: Missing parameter 'path'"); + } + if (!resource) { + throw new Error("Unable to create ResourceFacade: Missing parameter 'resource'"); + } + path = posixPath.normalize(path); + if (!posixPath.isAbsolute(path)) { + throw new Error(`Unable to create ResourceFacade: Parameter 'path' must be absolute: ${path}`); + } + this.#path = path; + this.#name = posixPath.basename(path); + this.#resource = resource; + } + /** + * Gets the resources path + * + * @public + * @returns {string} (Virtual) path of the resource + */ + getPath() { + return this.#path; + } + /** + * Gets the resource name + * + * @public + * @returns {string} Name of the resource + */ + getName() { + return this.#name; + } + /** + * Sets the resources path + * + * @public + * @param {string} path (Virtual) path of the resource + */ + setPath(path) { + throw new Error(`The path of a ResourceFacade can't be changed`); + } + /** + * Returns a clone of the resource. The clones content is independent from that of the original resource. + * A ResourceFacade becomes a Resource + * + * @public + * @returns {Promise<@ui5/fs/Resource>} Promise resolving with the clone + */ + async clone() { + // Cloning resolves the facade + const resourceClone = await this.#resource.clone(); + resourceClone.setPath(this.getPath()); + return resourceClone; + } + /** + * ====================================================================== + * Call through functions to original resource + * ====================================================================== + */ + /** + * Gets a buffer with the resource content. + * + * @public + * @returns {Promise} Promise resolving with a buffer of the resource content. + */ + async getBuffer() { + return this.#resource.getBuffer(); + } + /** + * Sets a Buffer as content. + * + * @public + * @param {Buffer} buffer Buffer instance + */ + setBuffer(buffer) { + return this.#resource.setBuffer(buffer); + } + /** + * Gets a string with the resource content. + * + * @public + * @returns {Promise} Promise resolving with the resource content. + */ + getString() { + return this.#resource.getString(); + } + /** + * Sets a String as content + * + * @public + * @param {string} string Resource content + */ + setString(string) { + return this.#resource.setString(string); + } + /** + * Gets a readable stream for the resource content. + * + * Repetitive calls of this function are only possible if new content has been set in the meantime (through + * [setStream]{@link @ui5/fs/Resource#setStream}, [setBuffer]{@link @ui5/fs/Resource#setBuffer} + * or [setString]{@link @ui5/fs/Resource#setString}). This + * is to prevent consumers from accessing drained streams. + * + * @public + * @returns {stream.Readable} Readable stream for the resource content. + */ + getStream() { + return this.#resource.getStream(); + } + /** + * Sets a readable stream as content. + * + * @public + * @param {stream.Readable|@ui5/fs/Resource~createStream} stream Readable stream of the resource content or + callback for dynamic creation of a readable stream + */ + setStream(stream) { + return this.#resource.setStream(stream); + } + /** + * Gets the resources stat info. + * Note that a resources stat information is not updated when the resource is being modified. + * Also, depending on the used adapter, some fields might be missing which would be present for a + * [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} instance. + * + * @public + * @returns {fs.Stats|object} Instance of [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} + * or similar object + */ + getStatInfo() { + return this.#resource.getStatInfo(); + } + /** + * Size in bytes allocated by the underlying buffer. + * + * @see {TypedArray#byteLength} + * @returns {Promise} size in bytes, 0 if there is no content yet + */ + async getSize() { + return this.#resource.getSize(); + } + /** + * Adds a resource collection name that was involved in locating this resource. + * + * @param {string} name Resource collection name + */ + pushCollection(name) { + return this.#resource.pushCollection(name); + } + /** + * Tracing: Get tree for printing out trace + * + * @returns {object} Trace tree + */ + getPathTree() { + return this.#resource.getPathTree(); + } + /** + * Retrieve the project assigned to the resource + *
+ * Note for UI5 Tooling extensions (i.e. custom tasks, custom middleware): + * In order to ensure compatibility across UI5 Tooling versions, consider using the + * getProject(resource) method provided by + * [TaskUtil]{@link module:@ui5/project/build/helpers/TaskUtil} and + * [MiddlewareUtil]{@link module:@ui5/server.middleware.MiddlewareUtil}, which will + * return a Specification Version-compatible Project interface. + * + * @public + * @returns {@ui5/project/specifications/Project} Project this resource is associated with + */ + getProject() { + return this.#resource.getProject(); + } + /** + * Assign a project to the resource + * + * @public + * @param {@ui5/project/specifications/Project} project Project this resource is associated with + */ + setProject(project) { + return this.#resource.setProject(project); + } + /** + * Check whether a project has been assigned to the resource + * + * @public + * @returns {boolean} True if the resource is associated with a project + */ + hasProject() { + return this.#resource.hasProject(); + } + /** + * Check whether the content of this resource has been changed during its life cycle + * + * @public + * @returns {boolean} True if the resource's content has been changed + */ + isModified() { + return this.#resource.isModified(); + } + /** + * Returns source metadata if any where provided during the creation of this resource. + * Typically set by an adapter to store information for later retrieval. + * + * @returns {object|null} + */ + getSourceMetadata() { + return this.#resource.getSourceMetadata(); + } + /** + * Returns the resource concealed by this facade + * + * @returns {@ui5/fs/Resource} + */ + getConcealedResource() { + return this.#resource; + } +} +export default ResourceFacade; +//# sourceMappingURL=ResourceFacade.js.map \ No newline at end of file diff --git a/lib/ResourceFacade.js.map b/lib/ResourceFacade.js.map new file mode 100644 index 00000000..fd68e837 --- /dev/null +++ b/lib/ResourceFacade.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ResourceFacade.js","sourceRoot":"","sources":["../src/ResourceFacade.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AAExC;;;;;;GAMG;AACH,MAAM,cAAc;IACnB,KAAK,CAAC;IACN,KAAK,CAAC;IACN,SAAS,CAAC;IAEV;;;;;;OAMG;IACH,YAAY,EAAC,IAAI,EAAE,QAAQ,EAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC9E,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,uEAAuE,IAAI,EAAE,CAAC,CAAC;QAChG,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;;;OAKG;IACH,OAAO;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACH,OAAO;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,IAAI;QACX,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAClE,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,KAAK;QACV,8BAA8B;QAC9B,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACnD,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACtC,OAAO,aAAa,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACH;;;;;OAKG;IACH,KAAK,CAAC,SAAS;QACd,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAC,MAAM;QACf,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACH,SAAS;QACR,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAC,MAAM;QACf,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;;;;;OAUG;IACH,SAAS;QACR,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;IACnC,CAAC;IAED;;;;;;OAMG;IACH,SAAS,CAAC,MAAM;QACf,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;;;;OASG;IACH,WAAW;QACV,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;IACrC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO;QACZ,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,IAAI;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED;;;;OAIG;IACH,WAAW;QACV,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;IACrC,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,UAAU;QACT,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;IACpC,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,OAAO;QACjB,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;OAKG;IACH,UAAU;QACT,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;IACpC,CAAC;IACD;;;;;OAKG;IACH,UAAU;QACT,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;IACpC,CAAC;IAED;;;;;OAKG;IACH,iBAAiB;QAChB,OAAO,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,CAAC;IAC3C,CAAC;IAGD;;;;OAIG;IACH,oBAAoB;QACnB,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;CACD;AAED,eAAe,cAAc,CAAC"} \ No newline at end of file diff --git a/lib/ResourceTagCollection.js b/lib/ResourceTagCollection.js new file mode 100644 index 00000000..7867666c --- /dev/null +++ b/lib/ResourceTagCollection.js @@ -0,0 +1,107 @@ +const tagNamespaceRegExp = /^[a-z][a-z0-9]+$/; // part before the colon +const tagNameRegExp = /^[A-Z][A-Za-z0-9]+$/; // part after the colon +import ResourceFacade from "./ResourceFacade.js"; +/** + * A ResourceTagCollection + * + * @private + * @class + * @alias @ui5/fs/internal/ResourceTagCollection + */ +class ResourceTagCollection { + constructor({ allowedTags = [], allowedNamespaces = [], tags }) { + this._allowedTags = allowedTags; // Allowed tags are validated during use + this._allowedNamespaces = allowedNamespaces; + if (allowedNamespaces.length) { + let allowedNamespacesRegExp = allowedNamespaces.reduce((regex, tagNamespace, idx) => { + // Ensure alphanum namespace to ensure working regex + if (!tagNamespaceRegExp.test(tagNamespace)) { + throw new Error(`Invalid namespace ${tagNamespace}: ` + + `Namespace must be alphanumeric, lowercase and start with a letter`); + } + return `${regex}${idx === 0 ? "" : "|"}${tagNamespace}`; + }, "^(?:"); + allowedNamespacesRegExp += "):.+$"; + this._allowedNamespacesRegExp = new RegExp(allowedNamespacesRegExp); + } + else { + this._allowedNamespacesRegExp = null; + } + this._pathTags = tags || Object.create(null); + } + setTag(resourcePath, tag, value = true) { + resourcePath = this._getPath(resourcePath); + this._validateTag(tag); + this._validateValue(value); + if (!this._pathTags[resourcePath]) { + this._pathTags[resourcePath] = Object.create(null); + } + this._pathTags[resourcePath][tag] = value; + } + clearTag(resourcePath, tag) { + resourcePath = this._getPath(resourcePath); + this._validateTag(tag); + if (this._pathTags[resourcePath]) { + this._pathTags[resourcePath][tag] = undefined; + } + } + getTag(resourcePath, tag) { + resourcePath = this._getPath(resourcePath); + this._validateTag(tag); + if (this._pathTags[resourcePath]) { + return this._pathTags[resourcePath][tag]; + } + } + getAllTags() { + return this._pathTags; + } + acceptsTag(tag) { + if (this._allowedTags.includes(tag) || this._allowedNamespacesRegExp?.test(tag)) { + return true; + } + return false; + } + _getPath(resourcePath) { + if (typeof resourcePath !== "string") { + if (resourcePath instanceof ResourceFacade) { + resourcePath = resourcePath.getConcealedResource().getPath(); + } + else { + resourcePath = resourcePath.getPath(); + } + } + if (!resourcePath) { + throw new Error(`Invalid Resource: Resource path must not be empty`); + } + return resourcePath; + } + _validateTag(tag) { + if (!tag.includes(":")) { + throw new Error(`Invalid Tag "${tag}": Colon required after namespace`); + } + const parts = tag.split(":"); + if (parts.length > 2) { + throw new Error(`Invalid Tag "${tag}": Expected exactly one colon but found ${parts.length - 1}`); + } + const [tagNamespace, tagName] = parts; + if (!tagNamespaceRegExp.test(tagNamespace)) { + throw new Error(`Invalid Tag "${tag}": Namespace part must be alphanumeric, lowercase and start with a letter`); + } + if (!tagNameRegExp.test(tagName)) { + throw new Error(`Invalid Tag "${tag}": Name part must be alphanumeric and start with a capital letter`); + } + if (!this.acceptsTag(tag)) { + throw new Error(`Tag "${tag}" not accepted by this collection. Accepted tags are: ` + + `${this._allowedTags.join(", ") || "*none*"}. Accepted namespaces are: ` + + `${this._allowedNamespaces.join(", ") || "*none*"}`); + } + } + _validateValue(value) { + const type = typeof value; + if (!["string", "number", "boolean"].includes(type)) { + throw new Error(`Invalid Tag Value: Must be of type string, number or boolean but is ${type}`); + } + } +} +export default ResourceTagCollection; +//# sourceMappingURL=ResourceTagCollection.js.map \ No newline at end of file diff --git a/lib/ResourceTagCollection.js.map b/lib/ResourceTagCollection.js.map new file mode 100644 index 00000000..ed5cd63e --- /dev/null +++ b/lib/ResourceTagCollection.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ResourceTagCollection.js","sourceRoot":"","sources":["../src/ResourceTagCollection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/WriterCollection.js b/lib/WriterCollection.js new file mode 100644 index 00000000..1985e53e --- /dev/null +++ b/lib/WriterCollection.js @@ -0,0 +1,105 @@ +import AbstractReaderWriter from "./AbstractReaderWriter.js"; +import ReaderCollection from "./ReaderCollection.js"; +import escapeStringRegExp from "escape-string-regexp"; +/** + * Resource Locator WriterCollection + * + * @public + * @class + * @alias @ui5/fs/WriterCollection + * @extends @ui5/fs/AbstractReaderWriter + */ +class WriterCollection extends AbstractReaderWriter { + /** + * The constructor. + * + * @param {object} parameters Parameters + * @param {string} parameters.name The collection name + * @param {object.} parameters.writerMapping + * Mapping of virtual base paths to writers. Path are matched greedy + * + * @example + * new WriterCollection({ + * name: "Writer Collection", + * writerMapping: { + * "/": writerA, + * "/my/path/": writerB, + * } + * }); + */ + constructor({ name, writerMapping }) { + super(name); + if (!writerMapping) { + throw new Error(`Cannot create WriterCollection ${this._name}: Missing parameter 'writerMapping'`); + } + const basePaths = Object.keys(writerMapping); + if (!basePaths.length) { + throw new Error(`Cannot create WriterCollection ${this._name}: Empty parameter 'writerMapping'`); + } + // Create a regular expression (which is greedy by nature) from all paths to easily + // find the correct writer for any given resource path + this._basePathRegex = basePaths.sort().reduce((regex, basePath, idx) => { + // Validate base path + if (!basePath) { + throw new Error(`Empty path in path mapping of WriterCollection ${this._name}`); + } + if (!basePath.startsWith("/")) { + throw new Error(`Missing leading slash in path mapping '${basePath}' of WriterCollection ${this._name}`); + } + if (!basePath.endsWith("/")) { + throw new Error(`Missing trailing slash in path mapping '${basePath}' of WriterCollection ${this._name}`); + } + return `${regex}(?:${escapeStringRegExp(basePath)})??`; + }, "^(") + ")+.*?$"; + this._writerMapping = writerMapping; + this._readerCollection = new ReaderCollection({ + name: `Reader collection of writer collection '${this._name}'`, + readers: Object.values(writerMapping) + }); + } + /** + * Locates resources by glob. + * + * @private + * @param {string|string[]} pattern glob pattern as string or an array of + * glob patterns for virtual directory structure + * @param {object} options glob options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + */ + _byGlob(pattern, options, trace) { + return this._readerCollection._byGlob(pattern, options, trace); + } + /** + * Locates resources by path. + * + * @private + * @param {string} virPath Virtual path + * @param {object} options Options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + */ + _byPath(virPath, options, trace) { + return this._readerCollection._byPath(virPath, options, trace); + } + /** + * Writes the content of a resource to a path. + * + * @private + * @param {@ui5/fs/Resource} resource The Resource to write + * @param {object} [options] Write options, see above + * @returns {Promise} Promise resolving once data has been written + */ + _write(resource, options) { + const resourcePath = resource.getPath(); + const basePathMatch = resourcePath.match(this._basePathRegex); + if (!basePathMatch || basePathMatch.length < 2) { + throw new Error(`Failed to find a writer for resource with path ${resourcePath} in WriterCollection ${this._name}. ` + + `Base paths handled by this collection are: ${Object.keys(this._writerMapping).join(", ")}`); + } + const writer = this._writerMapping[basePathMatch[1]]; + return writer._write(resource, options); + } +} +export default WriterCollection; +//# sourceMappingURL=WriterCollection.js.map \ No newline at end of file diff --git a/lib/WriterCollection.js.map b/lib/WriterCollection.js.map new file mode 100644 index 00000000..9ac8dbca --- /dev/null +++ b/lib/WriterCollection.js.map @@ -0,0 +1 @@ +{"version":3,"file":"WriterCollection.js","sourceRoot":"","sources":["../src/WriterCollection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/adapters/AbstractAdapter.js b/lib/adapters/AbstractAdapter.js new file mode 100644 index 00000000..a61f9156 --- /dev/null +++ b/lib/adapters/AbstractAdapter.js @@ -0,0 +1,280 @@ +import path from "node:path/posix"; +import { getLogger } from "@ui5/logger"; +const log = getLogger("resources:adapters:AbstractAdapter"); +import { minimatch } from "minimatch"; +import micromatch from "micromatch"; +import AbstractReaderWriter from "../AbstractReaderWriter.js"; +import Resource from "../Resource.js"; +/** + * Abstract Resource Adapter + * + * @abstract + * @public + * @class + * @alias @ui5/fs/adapters/AbstractAdapter + * @extends @ui5/fs/AbstractReaderWriter + */ +class AbstractAdapter extends AbstractReaderWriter { + /** + * The constructor + * + * @public + * @param {object} parameters Parameters + * @param {string} parameters.virBasePath + * Virtual base path. Must be absolute, POSIX-style, and must end with a slash + * @param {string[]} [parameters.excludes] List of glob patterns to exclude + * @param {object} [parameters.project] Experimental, internal parameter. Do not use + */ + constructor({ virBasePath, excludes = [], project }) { + if (new.target === AbstractAdapter) { + throw new TypeError("Class 'AbstractAdapter' is abstract"); + } + super(); + if (!virBasePath) { + throw new Error(`Unable to create adapter: Missing parameter 'virBasePath'`); + } + if (!path.isAbsolute(virBasePath)) { + throw new Error(`Unable to create adapter: Virtual base path must be absolute but is '${virBasePath}'`); + } + if (!virBasePath.endsWith("/")) { + throw new Error(`Unable to create adapter: Virtual base path must end with a slash but is '${virBasePath}'`); + } + this._virBasePath = virBasePath; + this._virBaseDir = virBasePath.slice(0, -1); + this._excludes = excludes; + this._excludesNegated = excludes.map((pattern) => `!${pattern}`); + this._project = project; + } + /** + * Locates resources by glob. + * + * @abstract + * @private + * @param {string|string[]} virPattern glob pattern as string or an array of + * glob patterns for virtual directory structure + * @param {object} [options={}] glob options + * @param {boolean} [options.nodir=true] Do not match directories + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + */ + async _byGlob(virPattern, options = { nodir: true }, trace) { + const excludes = this._excludesNegated; + if (!(virPattern instanceof Array)) { + virPattern = [virPattern]; + } + // Append static exclude patterns + virPattern = Array.prototype.concat.apply(virPattern, excludes); + let patterns = virPattern.map(this._normalizePattern, this); + patterns = Array.prototype.concat.apply([], patterns); + if (patterns.length === 0) { + return []; + } + if (!options.nodir) { + for (let i = patterns.length - 1; i >= 0; i--) { + const idx = this._virBaseDir.indexOf(patterns[i]); + if (patterns[i] && idx !== -1 && idx < this._virBaseDir.length) { + const subPath = patterns[i]; + return [ + this._createResource({ + statInfo: { + isDirectory: function () { + return true; + } + }, + source: { + adapter: "Abstract" + }, + path: subPath + }) + ]; + } + } + } + return await this._runGlob(patterns, options, trace); + } + /** + * Validate if virtual path should be excluded + * + * @param {string} virPath Virtual Path + * @returns {boolean} True if path is excluded, otherwise false + */ + _isPathExcluded(virPath) { + return micromatch(virPath, this._excludes).length > 0; + } + /** + * Validate if virtual path should be handled by the adapter. + * This means that it either starts with the virtual base path of the adapter + * or equals the base directory (base path without a trailing slash) + * + * @param {string} virPath Virtual Path + * @returns {boolean} True if path should be handled + */ + _isPathHandled(virPath) { + // Check whether path starts with base path, or equals base directory + return virPath.startsWith(this._virBasePath) || virPath === this._virBaseDir; + } + /** + * Normalizes virtual glob patterns. + * + * @private + * @param {string} virPattern glob pattern for virtual directory structure + * @returns {string[]} A list of normalized glob patterns + */ + _normalizePattern(virPattern) { + const that = this; + const mm = new minimatch.Minimatch(virPattern); + const basePathParts = this._virBaseDir.split("/"); + function matchSubset(subset) { + let i; + for (i = 0; i < basePathParts.length; i++) { + const globPart = subset[i]; + if (globPart === undefined) { + log.verbose("Ran out of glob parts to match (this should not happen):"); + if (that._project) { // project is optional + log.verbose(`Project: ${that._project.getName()}`); + } + log.verbose(`Virtual base path: ${that._virBaseDir}`); + log.verbose(`Pattern to match: ${virPattern}`); + log.verbose(`Current subset (tried index ${i}):`); + log.verbose(subset); + return { idx: i, virtualMatch: true }; + } + const basePathPart = basePathParts[i]; + if (typeof globPart === "string") { + if (globPart !== basePathPart) { + return null; + } + else { + continue; + } + } + else if (globPart === minimatch.GLOBSTAR) { + return { idx: i }; + } + else { // Regex + if (!globPart.test(basePathPart)) { + return null; + } + else { + continue; + } + } + } + if (subset.length === basePathParts.length) { + return { rootMatch: true }; + } + return { idx: i }; + } + const resultGlobs = []; + for (let i = 0; i < mm.set.length; i++) { + const match = matchSubset(mm.set[i]); + if (match) { + let resultPattern; + if (match.virtualMatch) { + resultPattern = basePathParts.slice(0, match.idx).join("/"); + } + else if (match.rootMatch) { // matched one up + resultPattern = ""; // root "/" + } + else { // matched at some part of the glob + resultPattern = mm.globParts[i].slice(match.idx).join("/"); + if (resultPattern.startsWith("/")) { + resultPattern = resultPattern.substr(1); + } + } + if (mm.negate) { + resultPattern = "!" + resultPattern; + } + resultGlobs.push(resultPattern); + } + } + return resultGlobs; + } + _createResource(parameters) { + if (this._project) { + parameters.project = this._project; + } + return new Resource(parameters); + } + _migrateResource(resource) { + // This function only returns a promise if a migration is necessary. + // Since this is rarely the case, we therefore reduce the amount of + // created Promises by making this differentiation + // Check if its a fs/Resource v3, function 'hasProject' was + // introduced with v3 therefore take it as the indicator + if (resource.hasProject) { + return resource; + } + return this._createFromLegacyResource(resource); + } + async _createFromLegacyResource(resource) { + const options = { + path: resource._path, + statInfo: resource._statInfo, + source: resource._source + }; + if (resource._stream) { + options.buffer = await resource._getBufferFromStream(); + } + else if (resource._createStream) { + options.createStream = resource._createStream; + } + else if (resource._buffer) { + options.buffer = resource._buffer; + } + return new Resource(options); + } + _assignProjectToResource(resource) { + if (this._project) { + // Assign project to resource if necessary + if (resource.hasProject()) { + if (resource.getProject() !== this._project) { + throw new Error(`Unable to write resource associated with project ` + + `${resource.getProject().getName()} into adapter of project ${this._project.getName()}: ` + + resource.getPath()); + } + return; + } + log.silly(`Associating resource ${resource.getPath()} with project ${this._project.getName()}`); + resource.setProject(this._project); + } + } + _resolveVirtualPathToBase(inputVirPath, writeMode = false) { + if (!path.isAbsolute(inputVirPath)) { + throw new Error(`Failed to resolve virtual path '${inputVirPath}': Path must be absolute`); + } + // Resolve any ".." segments to make sure we compare the effective start of the path + // with the virBasePath + const virPath = path.normalize(inputVirPath); + if (!writeMode) { + // When reading resources, validate against path excludes and return null if the given path + // does not match this adapters base path + if (!this._isPathHandled(virPath)) { + if (log.isLevelEnabled("silly")) { + log.silly(`Failed to resolve virtual path '${inputVirPath}': ` + + `Resolved path does not start with adapter base path '${this._virBasePath}' or equals ` + + `base dir: ${this._virBaseDir}`); + } + return null; + } + if (this._isPathExcluded(virPath)) { + if (log.isLevelEnabled("silly")) { + log.silly(`Failed to resolve virtual path '${inputVirPath}': ` + + `Resolved path is excluded by configuration of adapter with base path '${this._virBasePath}'`); + } + return null; + } + } + else if (!this._isPathHandled(virPath)) { + // Resolved path is not within the configured base path and does + // not equal the virtual base directory. + // Since we don't want to write resources to foreign locations, we throw an error + throw new Error(`Failed to write resource with virtual path '${inputVirPath}': Path must start with ` + + `the configured virtual base path of the adapter. Base path: '${this._virBasePath}'`); + } + const relPath = virPath.substr(this._virBasePath.length); + return relPath; + } +} +export default AbstractAdapter; +//# sourceMappingURL=AbstractAdapter.js.map \ No newline at end of file diff --git a/lib/adapters/AbstractAdapter.js.map b/lib/adapters/AbstractAdapter.js.map new file mode 100644 index 00000000..f4b005cf --- /dev/null +++ b/lib/adapters/AbstractAdapter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"AbstractAdapter.js","sourceRoot":"","sources":["../../src/adapters/AbstractAdapter.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/adapters/FileSystem.js b/lib/adapters/FileSystem.js new file mode 100644 index 00000000..da75473e --- /dev/null +++ b/lib/adapters/FileSystem.js @@ -0,0 +1,345 @@ +import { getLogger } from "@ui5/logger"; +const log = getLogger("resources:adapters:FileSystem"); +import path from "node:path"; +import { promisify } from "node:util"; +import fs from "graceful-fs"; +const copyFile = promisify(fs.copyFile); +const chmod = promisify(fs.chmod); +const mkdir = promisify(fs.mkdir); +const stat = promisify(fs.stat); +import { globby, isGitIgnored } from "globby"; +import { PassThrough } from "node:stream"; +import AbstractAdapter from "./AbstractAdapter.js"; +const READ_ONLY_MODE = 0o444; +const ADAPTER_NAME = "FileSystem"; +/** + * File system resource adapter + * + * @public + * @class + * @alias @ui5/fs/adapters/FileSystem + * @extends @ui5/fs/adapters/AbstractAdapter + */ +class FileSystem extends AbstractAdapter { + /** + * The Constructor. + * + * @param {object} parameters Parameters + * @param {string} parameters.virBasePath + * Virtual base path. Must be absolute, POSIX-style, and must end with a slash + * @param {string} parameters.fsBasePath + * File System base path. Must be absolute and must use platform-specific path segment separators + * @param {string[]} [parameters.excludes] List of glob patterns to exclude + * @param {object} [parameters.useGitignore=false] + * Whether to apply any excludes defined in an optional .gitignore in the given fsBasePath directory + * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) + */ + constructor({ virBasePath, project, fsBasePath, excludes, useGitignore = false }) { + super({ virBasePath, project, excludes }); + if (!fsBasePath) { + throw new Error(`Unable to create adapter: Missing parameter 'fsBasePath'`); + } + // Ensure path is resolved to an absolute path, ending with a slash (or backslash on Windows) + // path.resolve will always remove any trailing segment separator + this._fsBasePath = path.join(path.resolve(fsBasePath), path.sep); + this._useGitignore = !!useGitignore; + } + /** + * Locate resources by glob. + * + * @private + * @param {Array} patterns Array of glob patterns + * @param {object} [options={}] glob options + * @param {boolean} [options.nodir=true] Do not match directories + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + */ + async _runGlob(patterns, options = { nodir: true }, trace) { + const opt = { + cwd: this._fsBasePath, + dot: true, + onlyFiles: options.nodir, + followSymbolicLinks: false, + gitignore: this._useGitignore, + }; + trace.globCall(); + const promises = []; + if (!opt.onlyFiles && patterns.includes("")) { // Match physical root directory + promises.push(new Promise((resolve, reject) => { + fs.stat(this._fsBasePath, (err, stat) => { + if (err) { + reject(err); + } + else { + resolve(this._createResource({ + project: this._project, + statInfo: stat, + path: this._virBaseDir, + sourceMetadata: { + adapter: ADAPTER_NAME, + fsPath: this._fsBasePath + }, + createStream: () => { + return fs.createReadStream(this._fsBasePath); + } + })); + } + }); + })); + } + // Remove empty string glob patterns + // Starting with globby v8 or v9 empty glob patterns "" act like "**" + // Micromatch throws on empty strings. We just ignore them since they are + // typically caused by our normalization in the AbstractAdapter + const globbyPatterns = patterns.filter((pattern) => { + return pattern !== ""; + }); + if (globbyPatterns.length > 0) { + const matches = await globby(globbyPatterns, opt); + for (let i = matches.length - 1; i >= 0; i--) { + promises.push(new Promise((resolve, reject) => { + const virPath = (this._virBasePath + matches[i]); + const relPath = this._resolveVirtualPathToBase(virPath); + if (relPath === null) { + // Match is likely outside adapter base path + log.verbose(`Failed to resolve virtual path of glob match '${virPath}': Path must start with ` + + `the configured virtual base path of the adapter. Base path: '${this._virBasePath}'`); + resolve(null); + } + const fsPath = this._resolveToFileSystem(relPath); + // Workaround for not getting the stat from the glob + fs.stat(fsPath, (err, stat) => { + if (err) { + reject(err); + } + else { + resolve(this._createResource({ + project: this._project, + statInfo: stat, + path: virPath, + sourceMetadata: { + adapter: ADAPTER_NAME, + fsPath: fsPath + }, + createStream: () => { + return fs.createReadStream(fsPath); + } + })); + } + }); + })); + } + } + const results = await Promise.all(promises); + // Flatten results + return Array.prototype.concat.apply([], results).filter(($) => $); + } + /** + * Locate a resource by path. + * + * @private + * @param {string} virPath Absolute virtual path + * @param {object} options Options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource or null if not found + */ + async _byPath(virPath, options, trace) { + const relPath = this._resolveVirtualPathToBase(virPath); + if (relPath === null) { + // Neither starts with basePath, nor equals baseDirectory + if (!options.nodir && this._virBasePath.startsWith(virPath)) { + // Create virtual directories for the virtual base path (which has to exist) + // TODO: Maybe improve this by actually matching the base paths segments to the virPath + return this._createResource({ + project: this._project, + statInfo: { + isDirectory: function () { + return true; + } + }, + path: virPath + }); + } + else { + return null; + } + } + const fsPath = this._resolveToFileSystem(relPath); + trace.pathCall(); + if (this._useGitignore) { + if (!this._isGitIgnored) { + this._isGitIgnored = await isGitIgnored({ + cwd: this._fsBasePath + }); + } + // Check whether path should be ignored + if (this._isGitIgnored(fsPath)) { + // Path is ignored by .gitignore + return null; + } + } + try { + const statInfo = await stat(fsPath); + if (options.nodir && statInfo.isDirectory()) { + return null; + } + const resourceOptions = { + project: this._project, + statInfo, + path: virPath, + sourceMetadata: { + adapter: ADAPTER_NAME, + fsPath + } + }; + if (!statInfo.isDirectory()) { + // Add content as lazy stream + resourceOptions.createStream = function () { + return fs.createReadStream(fsPath); + }; + } + return this._createResource(resourceOptions); + } + catch (err) { + if (err.code === "ENOENT") { // "File or directory does not exist" + return null; + } + else { + throw err; + } + } + } + /** + * Writes the content of a resource to a path. + * + * @private + * @param {@ui5/fs/Resource} resource Resource to write + * @param {object} [options] + * @param {boolean} [options.readOnly] Whether the resource content shall be written read-only + * Do not use in conjunction with the drain option. + * The written file will be used as the new source of this resources content. + * Therefore the written file should not be altered by any means. + * Activating this option might improve overall memory consumption. + * @param {boolean} [options.drain] Whether the resource content shall be emptied during the write process. + * Do not use in conjunction with the readOnly option. + * Activating this option might improve overall memory consumption. + * This should be used in cases where this is the last access to the resource. + * E.g. the final write of a resource after all processing is finished. + * @returns {Promise} Promise resolving once data has been written + */ + async _write(resource, { drain, readOnly }) { + resource = this._migrateResource(resource); + if (resource instanceof Promise) { + // Only await if the migrate function returned a promise + // Otherwise await would automatically create a Promise, causing unwanted overhead + resource = await resource; + } + this._assignProjectToResource(resource); + if (drain && readOnly) { + throw new Error(`Error while writing resource ${resource.getPath()}: ` + + "Do not use options 'drain' and 'readOnly' at the same time."); + } + const relPath = this._resolveVirtualPathToBase(resource.getPath(), true); + const fsPath = this._resolveToFileSystem(relPath); + const dirPath = path.dirname(fsPath); + await mkdir(dirPath, { recursive: true }); + const sourceMetadata = resource.getSourceMetadata(); + if (sourceMetadata && sourceMetadata.adapter === ADAPTER_NAME && sourceMetadata.fsPath) { + // Resource has been created by FileSystem adapter. This means it might require special handling + /* The following code covers these four conditions: + 1. FS-paths not equal + Resource not modified => Shortcut: Use fs.copyFile + 2. FS-paths equal + Resource not modified => Shortcut: Skip write altogether + 3. FS-paths equal + Resource modified => Drain stream into buffer. Later write from buffer as usual + 4. FS-paths not equal + Resource modified => No special handling. Write from stream or buffer + */ + if (sourceMetadata.fsPath !== fsPath && !sourceMetadata.contentModified) { + // Shortcut: fs.copyFile can be used when the resource hasn't been modified + log.silly(`Resource hasn't been modified. Copying resource from ${sourceMetadata.fsPath} to ${fsPath}`); + await copyFile(sourceMetadata.fsPath, fsPath); + if (readOnly) { + await chmod(fsPath, READ_ONLY_MODE); + } + return; + } + else if (sourceMetadata.fsPath === fsPath && !sourceMetadata.contentModified) { + log.silly(`Resource hasn't been modified, target path equals source path. Skipping write to ${fsPath}`); + if (readOnly) { + await chmod(fsPath, READ_ONLY_MODE); + } + return; + } + else if (sourceMetadata.fsPath === fsPath && sourceMetadata.contentModified) { + // Resource has been modified. Make sure all streams are drained to prevent + // issues caused by piping the original read-stream into a write-stream for the same path + await resource.getBuffer(); + } + else { /* Different paths + modifications require no special handling */ } + } + log.silly(`Writing to ${fsPath}`); + await new Promise((resolve, reject) => { + let contentStream; + if (drain || readOnly) { + // Stream will be drained + contentStream = resource.getStream(); + contentStream.on("error", (err) => { + reject(err); + }); + } + else { + // Transform stream into buffer before writing + contentStream = new PassThrough(); + const buffers = []; + contentStream.on("error", (err) => { + reject(err); + }); + contentStream.on("data", (data) => { + buffers.push(data); + }); + contentStream.on("end", () => { + const buffer = Buffer.concat(buffers); + resource.setBuffer(buffer); + }); + resource.getStream().pipe(contentStream); + } + const writeOptions = {}; + if (readOnly) { + writeOptions.mode = READ_ONLY_MODE; + } + const write = fs.createWriteStream(fsPath, writeOptions); + write.on("error", (err) => { + reject(err); + }); + write.on("close", (ex) => { + resolve(); + }); + contentStream.pipe(write); + }); + if (readOnly) { + if (sourceMetadata?.fsPath === fsPath) { + // When streaming into the same file, permissions need to be changed explicitly + await chmod(fsPath, READ_ONLY_MODE); + } + // In case of readOnly, we drained the stream and can now set a new callback + // for creating a stream from written file + // This should be identical to buffering the resource content in memory, since the written file + // can not be modified. + // We chose this approach to be more memory efficient in scenarios where readOnly is used + resource.setStream(function () { + return fs.createReadStream(fsPath); + }); + } + } + _resolveToFileSystem(relPath) { + const fsPath = path.join(this._fsBasePath, relPath); + if (!fsPath.startsWith(this._fsBasePath)) { + log.verbose(`Failed to resolve virtual path internally: ${relPath}`); + log.verbose(` Adapter base path: ${this._fsBasePath}`); + log.verbose(` Resulting path: ${fsPath}`); + throw new Error(`Error while resolving internal virtual path: '${relPath}' resolves ` + + `to a directory not accessible by this File System adapter instance`); + } + return fsPath; + } +} +export default FileSystem; +//# sourceMappingURL=FileSystem.js.map \ No newline at end of file diff --git a/lib/adapters/FileSystem.js.map b/lib/adapters/FileSystem.js.map new file mode 100644 index 00000000..0487c629 --- /dev/null +++ b/lib/adapters/FileSystem.js.map @@ -0,0 +1 @@ +{"version":3,"file":"FileSystem.js","sourceRoot":"","sources":["../../src/adapters/FileSystem.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/adapters/Memory.js b/lib/adapters/Memory.js new file mode 100644 index 00000000..e2f31208 --- /dev/null +++ b/lib/adapters/Memory.js @@ -0,0 +1,162 @@ +import { getLogger } from "@ui5/logger"; +const log = getLogger("resources:adapters:Memory"); +import micromatch from "micromatch"; +import AbstractAdapter from "./AbstractAdapter.js"; +const ADAPTER_NAME = "Memory"; +/** + * Virtual resource Adapter + * + * @public + * @class + * @alias @ui5/fs/adapters/Memory + * @extends @ui5/fs/adapters/AbstractAdapter + */ +class Memory extends AbstractAdapter { + /** + * The constructor. + * + * @public + * @param {object} parameters Parameters + * @param {string} parameters.virBasePath + * Virtual base path. Must be absolute, POSIX-style, and must end with a slash + * @param {string[]} [parameters.excludes] List of glob patterns to exclude + * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) + */ + constructor({ virBasePath, project, excludes }) { + super({ virBasePath, project, excludes }); + this._virFiles = Object.create(null); // map full of files + this._virDirs = Object.create(null); // map full of directories + } + /** + * Matches and returns resources from a given map (either _virFiles or _virDirs). + * + * @private + * @param {string[]} patterns + * @param {object} resourceMap + * @returns {Promise} + */ + async _matchPatterns(patterns, resourceMap) { + const resourcePaths = Object.keys(resourceMap); + const matchedPaths = micromatch(resourcePaths, patterns, { + dot: true + }); + return await Promise.all(matchedPaths.map((virPath) => { + const resource = resourceMap[virPath]; + if (resource) { + return this._cloneResource(resource); + } + })); + } + async _cloneResource(resource) { + const clonedResource = await resource.clone(); + if (this._project) { + clonedResource.setProject(this._project); + } + return clonedResource; + } + /** + * Locate resources by glob. + * + * @private + * @param {Array} patterns array of glob patterns + * @param {object} [options={}] glob options + * @param {boolean} [options.nodir=true] Do not match directories + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + */ + async _runGlob(patterns, options = { nodir: true }, trace) { + if (patterns[0] === "" && !options.nodir) { // Match virtual root directory + return [ + this._createResource({ + project: this._project, + statInfo: { + isDirectory: function () { + return true; + } + }, + sourceMetadata: { + adapter: ADAPTER_NAME + }, + path: this._virBasePath.slice(0, -1) + }) + ]; + } + let matchedResources = await this._matchPatterns(patterns, this._virFiles); + if (!options.nodir) { + const matchedDirs = await this._matchPatterns(patterns, this._virDirs); + matchedResources = matchedResources.concat(matchedDirs); + } + return matchedResources; + } + /** + * Locates resources by path. + * + * @private + * @param {string} virPath Virtual path + * @param {object} options Options + * @param {@ui5/fs/tracing.Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + */ + async _byPath(virPath, options, trace) { + const relPath = this._resolveVirtualPathToBase(virPath); + if (relPath === null) { + return null; + } + trace.pathCall(); + const resource = this._virFiles[relPath]; + if (!resource || (options.nodir && resource.getStatInfo().isDirectory())) { + return null; + } + else { + return await this._cloneResource(resource); + } + } + /** + * Writes the content of a resource to a path. + * + * @private + * @param {@ui5/fs/Resource} resource The Resource to write + * @returns {Promise} Promise resolving once data has been written + */ + async _write(resource) { + resource = this._migrateResource(resource); + if (resource instanceof Promise) { + // Only await if the migrate function returned a promise + // Otherwise await would automatically create a Promise, causing unwanted overhead + resource = await resource; + } + this._assignProjectToResource(resource); + const relPath = this._resolveVirtualPathToBase(resource.getPath(), true); + log.silly(`Writing to virtual path ${resource.getPath()}`); + this._virFiles[relPath] = await resource.clone(); + // Add virtual directories for all path segments of the written resource + // TODO: Add tests for all this + const pathSegments = relPath.split("/"); + pathSegments.pop(); // Remove last segment representing the resource itself + pathSegments.forEach((segment, i) => { + if (i >= 1) { + segment = pathSegments[i - 1] + "/" + segment; + } + pathSegments[i] = segment; + }); + for (let i = pathSegments.length - 1; i >= 0; i--) { + const segment = pathSegments[i]; + if (!this._virDirs[segment]) { + this._virDirs[segment] = this._createResource({ + project: this._project, + sourceMetadata: { + adapter: ADAPTER_NAME + }, + statInfo: { + isDirectory: function () { + return true; + } + }, + path: this._virBasePath + segment + }); + } + } + } +} +export default Memory; +//# sourceMappingURL=Memory.js.map \ No newline at end of file diff --git a/lib/adapters/Memory.js.map b/lib/adapters/Memory.js.map new file mode 100644 index 00000000..18b95875 --- /dev/null +++ b/lib/adapters/Memory.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Memory.js","sourceRoot":"","sources":["../../src/adapters/Memory.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/fsInterface.js b/lib/fsInterface.js new file mode 100644 index 00000000..d3af8b5e --- /dev/null +++ b/lib/fsInterface.js @@ -0,0 +1,90 @@ +function toPosix(inputPath) { + return inputPath.replace(/\\/g, "/"); +} +/** + * @public + * @module @ui5/fs/fsInterface + */ +/** + * Wraps readers to access them through a [Node.js fs]{@link https://nodejs.org/api/fs.html} styled interface. + * + * @public + * @function default + * @static + * @param {@ui5/fs/AbstractReader} reader Resource Reader or Collection + * + * @returns {object} Object with [Node.js fs]{@link https://nodejs.org/api/fs.html} styled functions + * [readFile]{@link https://nodejs.org/api/fs.html#fs_fs_readfile_path_options_callback}, + * [stat]{@link https://nodejs.org/api/fs.html#fs_fs_stat_path_options_callback}, + * [readdir]{@link https://nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback} and + * [mkdir]{@link https://nodejs.org/api/fs.html#fs_fs_mkdir_path_options_callback} + */ +function fsInterface(reader) { + return { + readFile(fsPath, options, callback) { + if (typeof options === "function") { + callback = options; + options = undefined; + } + if (typeof options === "string") { + options = { encoding: options }; + } + const posixPath = toPosix(fsPath); + reader.byPath(posixPath, { + nodir: false + }).then(function (resource) { + if (!resource) { + const error = new Error(`ENOENT: no such file or directory, open '${fsPath}'`); + error.code = "ENOENT"; // "File or directory does not exist" + callback(error); + return; + } + return resource.getBuffer().then(function (buffer) { + let res; + if (options && options.encoding) { + res = buffer.toString(options.encoding); + } + else { + res = buffer; + } + callback(null, res); + }); + }).catch(callback); + }, + stat(fsPath, callback) { + const posixPath = toPosix(fsPath); + reader.byPath(posixPath, { + nodir: false + }).then(function (resource) { + if (!resource) { + const error = new Error(`ENOENT: no such file or directory, stat '${fsPath}'`); + error.code = "ENOENT"; // "File or directory does not exist" + callback(error); + } + else { + callback(null, resource.getStatInfo()); + } + }).catch(callback); + }, + readdir(fsPath, callback) { + let posixPath = toPosix(fsPath); + if (!posixPath.match(/\/$/)) { + // Add trailing slash if not present + posixPath += "/"; + } + reader.byGlob(posixPath + "*", { + nodir: false + }).then((resources) => { + const files = resources.map((resource) => { + return resource.getName(); + }); + callback(null, files); + }).catch(callback); + }, + mkdir(fsPath, callback) { + setTimeout(callback, 0); + } + }; +} +export default fsInterface; +//# sourceMappingURL=fsInterface.js.map \ No newline at end of file diff --git a/lib/fsInterface.js.map b/lib/fsInterface.js.map new file mode 100644 index 00000000..1c3919ca --- /dev/null +++ b/lib/fsInterface.js.map @@ -0,0 +1 @@ +{"version":3,"file":"fsInterface.js","sourceRoot":"","sources":["../src/fsInterface.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/readers/Filter.js b/lib/readers/Filter.js new file mode 100644 index 00000000..0a8abc3b --- /dev/null +++ b/lib/readers/Filter.js @@ -0,0 +1,71 @@ +import AbstractReader from "../AbstractReader.js"; +/** + * A reader that allows dynamic filtering of resources passed through it + * + * @public + * @class + * @alias @ui5/fs/readers/Filter + * @extends @ui5/fs/AbstractReader + */ +class Filter extends AbstractReader { + /** + * Filter callback + * + * @public + * @callback @ui5/fs/readers/Filter~callback + * @param {@ui5/fs/Resource} resource Resource to test + * @returns {boolean} Whether to keep the resource + */ + /** + * Constructor + * + * @public + * @param {object} parameters Parameters + * @param {@ui5/fs/AbstractReader} parameters.reader The resource reader or collection to wrap + * @param {@ui5/fs/readers/Filter~callback} parameters.callback + * Filter function. Will be called for every resource read through this reader. + */ + constructor({ reader, callback }) { + super(); + if (!reader) { + throw new Error(`Missing parameter "reader"`); + } + if (!callback) { + throw new Error(`Missing parameter "callback"`); + } + this._reader = reader; + this._callback = callback; + } + /** + * Locates resources by glob. + * + * @private + * @param {string|string[]} pattern glob pattern as string or an array of + * glob patterns for virtual directory structure + * @param {object} options glob options + * @param {@ui5/fs/tracing/Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + */ + async _byGlob(pattern, options, trace) { + const result = await this._reader._byGlob(pattern, options, trace); + return result.filter(this._callback); + } + /** + * Locates resources by path. + * + * @private + * @param {string} virPath Virtual path + * @param {object} options Options + * @param {@ui5/fs/tracing/Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + */ + async _byPath(virPath, options, trace) { + const result = await this._reader._byPath(virPath, options, trace); + if (result && !this._callback(result)) { + return null; + } + return result; + } +} +export default Filter; +//# sourceMappingURL=Filter.js.map \ No newline at end of file diff --git a/lib/readers/Filter.js.map b/lib/readers/Filter.js.map new file mode 100644 index 00000000..b9e1ba6c --- /dev/null +++ b/lib/readers/Filter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Filter.js","sourceRoot":"","sources":["../../src/readers/Filter.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,MAAO,SAAQ,cAAc;IAClC;;;;;;;MAOE;IAEF;;;;;;;;OAQG;IACH,YAAY,EAAC,MAAM,EAAE,QAAQ,EAAC;QAC7B,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACjD,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QACpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QACnE,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QACpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QACnE,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC;CACD;AAED,eAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/readers/Link.js b/lib/readers/Link.js new file mode 100644 index 00000000..2487941e --- /dev/null +++ b/lib/readers/Link.js @@ -0,0 +1,131 @@ +import AbstractReader from "../AbstractReader.js"; +import ResourceFacade from "../ResourceFacade.js"; +import { prefixGlobPattern } from "../resourceFactory.js"; +import { getLogger } from "@ui5/logger"; +const log = getLogger("resources:readers:Link"); +/** + * A reader that allows for rewriting paths segments of all resources passed through it. + * + * @example + * import Link from "@ui5/fs/readers/Link"; + * const linkedReader = new Link({ + * reader: sourceReader, + * pathMapping: { + * linkPath: `/app`, + * targetPath: `/resources/my-app-name/` + * } + * }); + * + * // The following resolves with a @ui5/fs/ResourceFacade of the resource + * // located at "/resources/my-app-name/Component.js" in the sourceReader + * const resource = await linkedReader.byPath("/app/Component.js"); + * + * @public + * @class + * @alias @ui5/fs/readers/Link + * @extends @ui5/fs/AbstractReader + */ +class Link extends AbstractReader { + /** + * Path mapping for a [Link]{@link @ui5/fs/readers/Link} + * + * @public + * @typedef {object} @ui5/fs/readers/Link/PathMapping + * @property {string} linkPath Path to match and replace in the requested path or pattern + * @property {string} targetPath Path to use as a replacement in the request for the source reader + */ + /** + * Constructor + * + * @public + * @param {object} parameters Parameters + * @param {@ui5/fs/AbstractReader} parameters.reader The resource reader or collection to wrap + * @param {@ui5/fs/readers/Link/PathMapping} parameters.pathMapping + */ + constructor({ reader, pathMapping }) { + super(); + if (!reader) { + throw new Error(`Missing parameter "reader"`); + } + if (!pathMapping) { + throw new Error(`Missing parameter "pathMapping"`); + } + this._reader = reader; + this._pathMapping = pathMapping; + Link._validatePathMapping(pathMapping); + } + /** + * Locates resources by glob. + * + * @private + * @param {string|string[]} patterns glob pattern as string or an array of + * glob patterns for virtual directory structure + * @param {object} options glob options + * @param {@ui5/fs/tracing/Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + */ + async _byGlob(patterns, options, trace) { + if (!(patterns instanceof Array)) { + patterns = [patterns]; + } + patterns = patterns.map((pattern) => { + if (pattern.startsWith(this._pathMapping.linkPath)) { + pattern = pattern.substr(this._pathMapping.linkPath.length); + } + return prefixGlobPattern(pattern, this._pathMapping.targetPath); + }); + // Flatten prefixed patterns + patterns = Array.prototype.concat.apply([], patterns); + // Keep resource's internal path unchanged for now + const resources = await this._reader._byGlob(patterns, options, trace); + return resources.map((resource) => { + const resourcePath = resource.getPath(); + if (resourcePath.startsWith(this._pathMapping.targetPath)) { + return new ResourceFacade({ + resource, + path: this._pathMapping.linkPath + resourcePath.substr(this._pathMapping.targetPath.length) + }); + } + }); + } + /** + * Locates resources by path. + * + * @private + * @param {string} virPath Virtual path + * @param {object} options Options + * @param {@ui5/fs/tracing/Trace} trace Trace instance + * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + */ + async _byPath(virPath, options, trace) { + if (!virPath.startsWith(this._pathMapping.linkPath)) { + return null; + } + const targetPath = this._pathMapping.targetPath + virPath.substr(this._pathMapping.linkPath.length); + log.silly(`byPath: Rewriting virtual path ${virPath} to ${targetPath}`); + const resource = await this._reader._byPath(targetPath, options, trace); + if (resource) { + return new ResourceFacade({ + resource, + path: this._pathMapping.linkPath + resource.getPath().substr(this._pathMapping.targetPath.length) + }); + } + return null; + } + static _validatePathMapping({ linkPath, targetPath }) { + if (!linkPath) { + throw new Error(`Path mapping is missing attribute "linkPath"`); + } + if (!targetPath) { + throw new Error(`Path mapping is missing attribute "targetPath"`); + } + if (!linkPath.endsWith("/")) { + throw new Error(`Link path must end with a slash: ${linkPath}`); + } + if (!targetPath.endsWith("/")) { + throw new Error(`Target path must end with a slash: ${targetPath}`); + } + } +} +export default Link; +//# sourceMappingURL=Link.js.map \ No newline at end of file diff --git a/lib/readers/Link.js.map b/lib/readers/Link.js.map new file mode 100644 index 00000000..2d55add0 --- /dev/null +++ b/lib/readers/Link.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Link.js","sourceRoot":"","sources":["../../src/readers/Link.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/resourceFactory.js b/lib/resourceFactory.js new file mode 100644 index 00000000..3018ebe1 --- /dev/null +++ b/lib/resourceFactory.js @@ -0,0 +1,266 @@ +import path from "node:path"; +import { minimatch } from "minimatch"; +import DuplexCollection from "./DuplexCollection.js"; +import FsAdapter from "./adapters/FileSystem.js"; +import MemAdapter from "./adapters/Memory.js"; +import ReaderCollection from "./ReaderCollection.js"; +import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; +import Resource from "./Resource.js"; +import WriterCollection from "./WriterCollection.js"; +import Filter from "./readers/Filter.js"; +import Link from "./readers/Link.js"; +import { getLogger } from "@ui5/logger"; +const log = getLogger("resources:resourceFactory"); +/** + * @module @ui5/fs/resourceFactory + * @description A collection of resource related APIs + * @public + */ +/** + * Creates a resource ReaderWriter. + * + * If a file system base path is given, file system resource ReaderWriter is returned. + * In any other case a virtual one. + * + * @public + * @param {object} parameters Parameters + * @param {string} parameters.virBasePath Virtual base path. Must be absolute, POSIX-style, and must end with a slash + * @param {string} [parameters.fsBasePath] + * File System base path. + * If this parameter is supplied, a File System adapter will be created instead of a Memory adapter. + * The provided path must be absolute and must use platform-specific path segment separators. + * @param {string[]} [parameters.excludes] List of glob patterns to exclude + * @param {object} [parameters.useGitignore=false] + * Whether to apply any excludes defined in an optional .gitignore in the base directory. + * This parameter only takes effect in conjunction with the fsBasePath parameter. + * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) + * @returns {@ui5/fs/adapters/FileSystem|@ui5/fs/adapters/Memory} File System- or Virtual Adapter + */ +export function createAdapter({ fsBasePath, virBasePath, project, excludes, useGitignore }) { + if (fsBasePath) { + return new FsAdapter({ fsBasePath, virBasePath, project, excludes, useGitignore }); + } + else { + return new MemAdapter({ virBasePath, project, excludes }); + } +} +/** + * Creates a File System adapter and wraps it in a ReaderCollection + * + * @public + * @param {object} parameters Parameters + * @param {string} parameters.virBasePath Virtual base path. Must be absolute, POSIX-style, and must end with a slash + * @param {string} parameters.fsBasePath + * File System base path. Must be absolute and must use platform-specific path segment separators + * @param {object} [parameters.project] Experimental, internal parameter. Do not use + * @param {string[]} [parameters.excludes] List of glob patterns to exclude + * @param {string} [parameters.name] Name for the reader collection + * @returns {@ui5/fs/ReaderCollection} Reader collection wrapping an adapter + */ +export function createReader({ fsBasePath, virBasePath, project, excludes = [], name }) { + if (!fsBasePath) { + // Creating a reader with a memory adapter seems pointless right now + // since there would be no way to fill the adapter with resources + throw new Error(`Unable to create reader: Missing parameter "fsBasePath"`); + } + let normalizedExcludes = excludes; + // If a project is supplied, and that project is of type application, + // Prefix all exclude patterns with the virtual base path (unless it already starts with that) + // TODO 4.0: // TODO specVersion 4.0: Disallow excludes without namespaced prefix in configuration + // Specifying an exclude for "/test" is disambigous as it neither reflects the source path nor the + // ui5 runtime path of the excluded resources. Therefore, only allow paths like /resources//test + // starting with specVersion 4.0 + if (excludes.length && project && project.getType() === "application") { + normalizedExcludes = excludes.map((pattern) => { + if (pattern.startsWith(virBasePath) || pattern.startsWith("!" + virBasePath)) { + return pattern; + } + log.verbose(`Prefixing exclude pattern defined in application project ${project.getName()}: ${pattern}`); + return prefixGlobPattern(pattern, virBasePath); + }); + // Flatten list of patterns + normalizedExcludes = Array.prototype.concat.apply([], normalizedExcludes); + log.verbose(`Effective exclude patterns for application project ${project.getName()}:\n` + + normalizedExcludes.join(", ")); + } + return new ReaderCollection({ + name, + readers: [createAdapter({ + fsBasePath, + virBasePath, + project, + excludes: normalizedExcludes + })] + }); +} +/** + * Creates a ReaderCollection + * + * @public + * @param {object} parameters Parameters + * @param {string} parameters.name The collection name + * @param {@ui5/fs/AbstractReader[]} parameters.readers List of resource readers (all tried in parallel) + * @returns {@ui5/fs/ReaderCollection} Reader collection wrapping provided readers + */ +export function createReaderCollection({ name, readers }) { + return new ReaderCollection({ + name, + readers + }); +} +/** + * Creates a ReaderCollectionPrioritized + * + * @public + * @param {object} parameters + * @param {string} parameters.name The collection name + * @param {@ui5/fs/AbstractReader[]} parameters.readers Prioritized list of resource readers + * (first is tried first) + * @returns {@ui5/fs/ReaderCollectionPrioritized} Reader collection wrapping provided readers + */ +export function createReaderCollectionPrioritized({ name, readers }) { + return new ReaderCollectionPrioritized({ + name, + readers + }); +} +/** + * Creates a WriterCollection + * + * @public + * @param {object} parameters + * @param {string} parameters.name The collection name + * @param {object.} parameters.writerMapping Mapping of virtual base + * paths to writers. Path are matched greedy + * @returns {@ui5/fs/WriterCollection} Writer collection wrapping provided writers + */ +export function createWriterCollection({ name, writerMapping }) { + return new WriterCollection({ + name, + writerMapping + }); +} +/** + * Creates a [Resource]{@link @ui5/fs/Resource}. + * Accepts the same parameters as the [Resource]{@link @ui5/fs/Resource} constructor. + * + * @public + * @param {object} parameters Parameters to be passed to the resource constructor + * @returns {@ui5/fs/Resource} Resource + */ +export function createResource(parameters) { + return new Resource(parameters); +} +/** + * Creates a Workspace + * + * A workspace is a DuplexCollection which reads from the project sources. It is used during the build process + * to write modified files into a separate writer, this is usually a Memory adapter. If a file already exists it is + * fetched from the memory to work on it in further build steps. + * + * @public + * @param {object} parameters + * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers + * @param {@ui5/fs/AbstractReaderWriter} [parameters.writer] A ReaderWriter instance which is + * only used for writing files. If not supplied, a Memory adapter will be created. + * @param {string} [parameters.name="workspace"] Name of the collection + * @param {string} [parameters.virBasePath="/"] Virtual base path + * @returns {@ui5/fs/DuplexCollection} DuplexCollection which wraps the provided resource locators + */ +export function createWorkspace({ reader, writer, virBasePath = "/", name = "workspace" }) { + if (!writer) { + writer = new MemAdapter({ + virBasePath + }); + } + return new DuplexCollection({ + reader, + writer, + name + }); +} +/** + * Create a [Filter-Reader]{@link @ui5/fs/readers/Filter} with the given reader. + * The provided callback is called for every resource that is retrieved through the + * reader and decides whether the resource shall be passed on or dropped. + * + * @public + * @param {object} parameters + * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers + * @param {@ui5/fs/readers/Filter~callback} parameters.callback + * Filter function. Will be called for every resource passed through this reader. + * @returns {@ui5/fs/readers/Filter} Reader instance + */ +export function createFilterReader(parameters) { + return new Filter(parameters); +} +/** + * Create a [Link-Reader]{@link @ui5/fs/readers/Filter} with the given reader. + * The provided path mapping allows for rewriting paths segments of all resources passed through it. + * + * @example + * import {createLinkReader} from "@ui5/fs/resourceFactory"; + * const linkedReader = createLinkReader({ + * reader: sourceReader, + * pathMapping: { + * linkPath: `/app`, + * targetPath: `/resources/my-app-name/` + * } + * }); + * + * // The following resolves with a @ui5/fs/ResourceFacade of the resource + * // located at "/resources/my-app-name/Component.js" in the sourceReader + * const resource = await linkedReader.byPath("/app/Component.js"); + * + * @public + * @param {object} parameters + * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers + * @param {@ui5/fs/readers/Link/PathMapping} parameters.pathMapping + * @returns {@ui5/fs/readers/Link} Reader instance + */ +export function createLinkReader(parameters) { + return new Link(parameters); +} +/** + * Create a [Link-Reader]{@link @ui5/fs/readers/Link} where all requests are prefixed with + * /resources/. + * + * This simulates "flat" resource access, which is for example common for projects of type + * "application". + * + * @public + * @param {object} parameters + * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers + * @param {string} parameters.namespace Project namespace + * @returns {@ui5/fs/readers/Link} Reader instance + */ +export function createFlatReader({ reader, namespace }) { + return new Link({ + reader: reader, + pathMapping: { + linkPath: `/`, + targetPath: `/resources/${namespace}/` + } + }); +} +/** + * Normalizes virtual glob patterns by prefixing them with + * a given virtual base directory path + * + * @param {string} virPattern glob pattern for virtual directory structure + * @param {string} virBaseDir virtual base directory path to prefix the given patterns with + * @returns {string[]} A list of normalized glob patterns + */ +export function prefixGlobPattern(virPattern, virBaseDir) { + const mm = new minimatch.Minimatch(virPattern); + const resultGlobs = []; + for (let i = 0; i < mm.globSet.length; i++) { + let resultPattern = path.posix.join(virBaseDir, mm.globSet[i]); + if (mm.negate) { + resultPattern = "!" + resultPattern; + } + resultGlobs.push(resultPattern); + } + return resultGlobs; +} +//# sourceMappingURL=resourceFactory.js.map \ No newline at end of file diff --git a/lib/resourceFactory.js.map b/lib/resourceFactory.js.map new file mode 100644 index 00000000..9a3d430a --- /dev/null +++ b/lib/resourceFactory.js.map @@ -0,0 +1 @@ +{"version":3,"file":"resourceFactory.js","sourceRoot":"","sources":["../src/resourceFactory.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/tracing/Trace.js b/lib/tracing/Trace.js new file mode 100644 index 00000000..2b48e295 --- /dev/null +++ b/lib/tracing/Trace.js @@ -0,0 +1,91 @@ +import { getLogger } from "@ui5/logger"; +const log = getLogger("resources:tracing:Trace"); +const logGlobs = getLogger("resources:tracing:Trace:globs"); +const logPaths = getLogger("resources:tracing:Trace:paths"); +import prettyHrtime from "pretty-hrtime"; +import summaryTrace from "./traceSummary.js"; +const hasOwnProperty = Object.prototype.hasOwnProperty; +/** + * Trace + * + * @private + * @class + */ +class Trace { + constructor(name) { + if (!log.isLevelEnabled("silly")) { + return; + } + this._name = name; + this._startTime = process.hrtime(); + this._globCalls = 0; + this._pathCalls = 0; + this._collections = Object.create(null); + summaryTrace.traceStarted(); + } + globCall() { + if (!log.isLevelEnabled("silly")) { + return; + } + this._globCalls++; + summaryTrace.globCall(); + } + pathCall() { + if (!log.isLevelEnabled("silly")) { + return; + } + this._pathCalls++; + summaryTrace.pathCall(); + } + collection(name) { + if (!log.isLevelEnabled("silly")) { + return; + } + const collection = this._collections[name]; + if (collection) { + this._collections[name].calls++; + } + else { + this._collections[name] = { + calls: 1 + }; + } + summaryTrace.collection(name); + } + printReport() { + if (!log.isLevelEnabled("silly")) { + return; + } + let report = ""; + const timeDiff = process.hrtime(this._startTime); + const time = prettyHrtime(timeDiff); + const colCount = Object.keys(this._collections).length; + report += `[Trace: ${this._name}\n`; + report += ` ${time} elapsed time \n`; + if (this._globCalls) { + report += ` ${this._globCalls} glob executions\n`; + } + if (this._pathCalls) { + report += ` ${this._pathCalls} path stats\n`; + } + report += ` ${colCount} reader-collections involed:\n`; + for (const coll in this._collections) { + if (hasOwnProperty.call(this._collections, coll)) { + report += ` ${this._collections[coll].calls}x ${coll}\n`; + } + } + report += "======================]"; + if (this._globCalls && this._pathCalls) { + log.silly(report); + } + else if (this._globCalls) { + logGlobs.silly(report); + } + else { + logPaths.silly(report); + } + summaryTrace.traceEnded(); + } +} +export default Trace; +//# sourceMappingURL=Trace.js.map \ No newline at end of file diff --git a/lib/tracing/Trace.js.map b/lib/tracing/Trace.js.map new file mode 100644 index 00000000..955b8246 --- /dev/null +++ b/lib/tracing/Trace.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Trace.js","sourceRoot":"","sources":["../../src/tracing/Trace.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/tracing/traceSummary.js b/lib/tracing/traceSummary.js new file mode 100644 index 00000000..fb582f90 --- /dev/null +++ b/lib/tracing/traceSummary.js @@ -0,0 +1,113 @@ +import { getLogger } from "@ui5/logger"; +const log = getLogger("resources:tracing:total"); +import prettyHrtime from "pretty-hrtime"; +const hasOwnProperty = Object.prototype.hasOwnProperty; +let timeoutId; +let active = false; +let tracesRunning = 0; +let traceData; +function init() { + traceData = { + startTime: process.hrtime(), + pathCalls: 0, + globCalls: 0, + collections: {}, + traceCalls: 0 + }; + active = true; +} +function reset() { + traceData = null; + active = false; +} +function report() { + let report = ""; + const time = prettyHrtime(traceData.timeDiff); + const colCount = Object.keys(traceData.collections).length; + report += "==========================\n[=> TRACE SUMMARY:\n"; + report += ` ${time} elapsed time \n`; + report += ` ${traceData.traceCalls} trace calls \n`; + if (traceData.globCalls) { + report += ` ${traceData.globCalls} glob executions\n`; + } + if (traceData.pathCalls) { + report += ` ${traceData.pathCalls} path stats\n`; + } + report += ` ${colCount} rl-collections involed:\n`; + for (const coll in traceData.collections) { + if (hasOwnProperty.call(traceData.collections, coll)) { + report += ` ${traceData.collections[coll].calls}x ${coll}\n`; + } + } + report += "======================]"; + log.silly(report); +} +function someTraceStarted() { + if (!log.isLevelEnabled("silly")) { + return; + } + if (!traceData) { + init(); + } + tracesRunning++; + traceData.traceCalls++; + if (timeoutId) { + clearTimeout(timeoutId); + } +} +function someTraceEnded() { + return new Promise(function (resolve, reject) { + if (!active) { + resolve(); + return; + } + tracesRunning--; + if (tracesRunning > 0) { + resolve(); + return; + } + if (timeoutId) { + clearTimeout(timeoutId); + } + traceData.timeDiff = process.hrtime(traceData.startTime); + timeoutId = setTimeout(function () { + report(); + reset(); + resolve(); + }, 2000); + }); +} +function pathCall() { + if (!active) { + return; + } + traceData.pathCalls++; +} +function globCall() { + if (!active) { + return; + } + traceData.globCalls++; +} +function collection(name) { + if (!active) { + return; + } + const collection = traceData.collections[name]; + if (collection) { + traceData.collections[name].calls++; + } + else { + traceData.collections[name] = { + calls: 1 + }; + } +} +export default { + pathCall: pathCall, + globCall: globCall, + collection: collection, + traceStarted: someTraceStarted, + traceEnded: someTraceEnded +}; +//# sourceMappingURL=traceSummary.js.map \ No newline at end of file diff --git a/lib/tracing/traceSummary.js.map b/lib/tracing/traceSummary.js.map new file mode 100644 index 00000000..b2657e18 --- /dev/null +++ b/lib/tracing/traceSummary.js.map @@ -0,0 +1 @@ +{"version":3,"file":"traceSummary.js","sourceRoot":"","sources":["../../src/tracing/traceSummary.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/AbstractReader.js b/src/AbstractReader.ts similarity index 100% rename from src/AbstractReader.js rename to src/AbstractReader.ts diff --git a/src/AbstractReaderWriter.js b/src/AbstractReaderWriter.ts similarity index 100% rename from src/AbstractReaderWriter.js rename to src/AbstractReaderWriter.ts diff --git a/src/DuplexCollection.js b/src/DuplexCollection.ts similarity index 100% rename from src/DuplexCollection.js rename to src/DuplexCollection.ts diff --git a/src/ReaderCollection.js b/src/ReaderCollection.ts similarity index 100% rename from src/ReaderCollection.js rename to src/ReaderCollection.ts diff --git a/src/ReaderCollectionPrioritized.js b/src/ReaderCollectionPrioritized.ts similarity index 100% rename from src/ReaderCollectionPrioritized.js rename to src/ReaderCollectionPrioritized.ts diff --git a/src/Resource.js b/src/Resource.ts similarity index 100% rename from src/Resource.js rename to src/Resource.ts diff --git a/src/ResourceFacade.js b/src/ResourceFacade.ts similarity index 100% rename from src/ResourceFacade.js rename to src/ResourceFacade.ts diff --git a/src/ResourceTagCollection.js b/src/ResourceTagCollection.ts similarity index 100% rename from src/ResourceTagCollection.js rename to src/ResourceTagCollection.ts diff --git a/src/WriterCollection.js b/src/WriterCollection.ts similarity index 100% rename from src/WriterCollection.js rename to src/WriterCollection.ts diff --git a/src/adapters/AbstractAdapter.js b/src/adapters/AbstractAdapter.ts similarity index 100% rename from src/adapters/AbstractAdapter.js rename to src/adapters/AbstractAdapter.ts diff --git a/src/adapters/FileSystem.js b/src/adapters/FileSystem.ts similarity index 100% rename from src/adapters/FileSystem.js rename to src/adapters/FileSystem.ts diff --git a/src/adapters/Memory.js b/src/adapters/Memory.ts similarity index 100% rename from src/adapters/Memory.js rename to src/adapters/Memory.ts diff --git a/src/fsInterface.js b/src/fsInterface.ts similarity index 100% rename from src/fsInterface.js rename to src/fsInterface.ts diff --git a/src/readers/Filter.js b/src/readers/Filter.ts similarity index 100% rename from src/readers/Filter.js rename to src/readers/Filter.ts diff --git a/src/readers/Link.js b/src/readers/Link.ts similarity index 100% rename from src/readers/Link.js rename to src/readers/Link.ts diff --git a/src/resourceFactory.js b/src/resourceFactory.ts similarity index 100% rename from src/resourceFactory.js rename to src/resourceFactory.ts diff --git a/src/tracing/Trace.js b/src/tracing/Trace.ts similarity index 100% rename from src/tracing/Trace.js rename to src/tracing/Trace.ts diff --git a/src/tracing/traceSummary.js b/src/tracing/traceSummary.ts similarity index 100% rename from src/tracing/traceSummary.js rename to src/tracing/traceSummary.ts diff --git a/test/lib/AbstractReader.js b/test/lib/AbstractReader.ts similarity index 100% rename from test/lib/AbstractReader.js rename to test/lib/AbstractReader.ts diff --git a/test/lib/AbstractReaderWriter.js b/test/lib/AbstractReaderWriter.ts similarity index 100% rename from test/lib/AbstractReaderWriter.js rename to test/lib/AbstractReaderWriter.ts diff --git a/test/lib/DuplexCollection.js b/test/lib/DuplexCollection.ts similarity index 100% rename from test/lib/DuplexCollection.js rename to test/lib/DuplexCollection.ts diff --git a/test/lib/ReaderCollection.js b/test/lib/ReaderCollection.ts similarity index 100% rename from test/lib/ReaderCollection.js rename to test/lib/ReaderCollection.ts diff --git a/test/lib/ReaderCollectionPrioritized.js b/test/lib/ReaderCollectionPrioritized.ts similarity index 100% rename from test/lib/ReaderCollectionPrioritized.js rename to test/lib/ReaderCollectionPrioritized.ts diff --git a/test/lib/Resource.js b/test/lib/Resource.ts similarity index 100% rename from test/lib/Resource.js rename to test/lib/Resource.ts diff --git a/test/lib/ResourceFacade.js b/test/lib/ResourceFacade.ts similarity index 100% rename from test/lib/ResourceFacade.js rename to test/lib/ResourceFacade.ts diff --git a/test/lib/ResourceTagCollection.js b/test/lib/ResourceTagCollection.ts similarity index 100% rename from test/lib/ResourceTagCollection.js rename to test/lib/ResourceTagCollection.ts diff --git a/test/lib/WriterCollection.js b/test/lib/WriterCollection.ts similarity index 100% rename from test/lib/WriterCollection.js rename to test/lib/WriterCollection.ts diff --git a/test/lib/adapters/AbstractAdapter.js b/test/lib/adapters/AbstractAdapter.ts similarity index 100% rename from test/lib/adapters/AbstractAdapter.js rename to test/lib/adapters/AbstractAdapter.ts diff --git a/test/lib/adapters/FileSystem.js b/test/lib/adapters/FileSystem.ts similarity index 100% rename from test/lib/adapters/FileSystem.js rename to test/lib/adapters/FileSystem.ts diff --git a/test/lib/adapters/FileSystem_read.js b/test/lib/adapters/FileSystem_read.ts similarity index 100% rename from test/lib/adapters/FileSystem_read.js rename to test/lib/adapters/FileSystem_read.ts diff --git a/test/lib/adapters/FileSystem_write.js b/test/lib/adapters/FileSystem_write.ts similarity index 100% rename from test/lib/adapters/FileSystem_write.js rename to test/lib/adapters/FileSystem_write.ts diff --git a/test/lib/adapters/FileSystem_write_large_file.js b/test/lib/adapters/FileSystem_write_large_file.ts similarity index 100% rename from test/lib/adapters/FileSystem_write_large_file.js rename to test/lib/adapters/FileSystem_write_large_file.ts diff --git a/test/lib/adapters/Memory_read.js b/test/lib/adapters/Memory_read.ts similarity index 100% rename from test/lib/adapters/Memory_read.js rename to test/lib/adapters/Memory_read.ts diff --git a/test/lib/adapters/Memory_write.js b/test/lib/adapters/Memory_write.ts similarity index 100% rename from test/lib/adapters/Memory_write.js rename to test/lib/adapters/Memory_write.ts diff --git a/test/lib/fsInterface.js b/test/lib/fsInterface.ts similarity index 100% rename from test/lib/fsInterface.js rename to test/lib/fsInterface.ts diff --git a/test/lib/glob.js b/test/lib/glob.ts similarity index 100% rename from test/lib/glob.js rename to test/lib/glob.ts diff --git a/test/lib/package-exports.js b/test/lib/package-exports.ts similarity index 100% rename from test/lib/package-exports.js rename to test/lib/package-exports.ts diff --git a/test/lib/readers/Filter.js b/test/lib/readers/Filter.ts similarity index 100% rename from test/lib/readers/Filter.js rename to test/lib/readers/Filter.ts diff --git a/test/lib/readers/Link.js b/test/lib/readers/Link.ts similarity index 100% rename from test/lib/readers/Link.js rename to test/lib/readers/Link.ts diff --git a/test/lib/resourceFactory.js b/test/lib/resourceFactory.ts similarity index 100% rename from test/lib/resourceFactory.js rename to test/lib/resourceFactory.ts diff --git a/test/lib/resources.js b/test/lib/resources.ts similarity index 100% rename from test/lib/resources.js rename to test/lib/resources.ts diff --git a/test/lib/tracing/traceSummary.js b/test/lib/tracing/traceSummary.ts similarity index 100% rename from test/lib/tracing/traceSummary.js rename to test/lib/tracing/traceSummary.ts From ff190d9fdd4435ba2787d000b07be651586c6c47 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 10:30:55 +0300 Subject: [PATCH 04/69] fix: Auto fix some of the ESLint issues --- ava.config.js | 16 +- jsdoc-plugin.cjs | 4 +- src/AbstractReader.ts | 6 +- src/DuplexCollection.ts | 4 +- src/ReaderCollection.ts | 8 +- src/ReaderCollectionPrioritized.ts | 2 +- src/Resource.ts | 7 +- src/ResourceFacade.ts | 2 +- src/WriterCollection.ts | 2 +- src/adapters/AbstractAdapter.ts | 19 +-- src/adapters/FileSystem.ts | 26 ++-- src/adapters/Memory.ts | 20 +-- src/fsInterface.ts | 16 +- src/readers/Link.ts | 4 +- src/resourceFactory.ts | 20 +-- src/tracing/Trace.ts | 2 +- src/tracing/traceSummary.ts | 10 +- test/lib/AbstractReader.ts | 8 +- test/lib/AbstractReaderWriter.ts | 5 +- test/lib/DuplexCollection.ts | 48 +++--- test/lib/ReaderCollection.ts | 60 ++++---- test/lib/ReaderCollectionPrioritized.ts | 60 ++++---- test/lib/Resource.ts | 128 ++++++++-------- test/lib/ResourceFacade.ts | 22 +-- test/lib/ResourceTagCollection.ts | 96 ++++++------ test/lib/WriterCollection.ts | 62 ++++---- test/lib/adapters/AbstractAdapter.ts | 96 ++++++------ test/lib/adapters/FileSystem.ts | 4 +- test/lib/adapters/FileSystem_read.ts | 132 ++++++++-------- test/lib/adapters/FileSystem_write.ts | 8 +- .../adapters/FileSystem_write_large_file.ts | 4 +- test/lib/adapters/Memory_read.ts | 143 +++++++++--------- test/lib/adapters/Memory_write.ts | 46 +++--- test/lib/fsInterface.ts | 14 +- test/lib/glob.ts | 21 ++- test/lib/package-exports.ts | 28 ++-- test/lib/readers/Filter.ts | 24 +-- test/lib/readers/Link.ts | 84 +++++----- test/lib/resourceFactory.ts | 91 ++++++----- test/lib/resources.ts | 48 +++--- test/lib/tracing/traceSummary.ts | 8 +- 41 files changed, 702 insertions(+), 706 deletions(-) diff --git a/ava.config.js b/ava.config.js index 32b18f7f..a256173d 100644 --- a/ava.config.js +++ b/ava.config.js @@ -5,17 +5,17 @@ const nodeArguments = [ ]; export default { - "extensions": { + extensions: { ts: "module", }, - "files": [ - "test/lib/**/*.ts" + files: [ + "test/lib/**/*.ts", ], - "watchMode": { - "ignoreChanges": [ - "test/tmp/**" - ] + watchMode: { + ignoreChanges: [ + "test/tmp/**", + ], }, nodeArguments, - "workerThreads": false + workerThreads: false, }; diff --git a/jsdoc-plugin.cjs b/jsdoc-plugin.cjs index cd7ef446..4305acfe 100644 --- a/jsdoc-plugin.cjs +++ b/jsdoc-plugin.cjs @@ -3,7 +3,7 @@ * JSDoc doesn't see "{@" as a valid type expression, probably as there's also {@link ...}. */ exports.handlers = { - jsdocCommentFound: function(e) { + jsdocCommentFound: function (e) { e.comment = e.comment.replace(/{@ui5\//g, "{ @ui5/"); - } + }, }; diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index 8f5c3632..4cc5309c 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -49,7 +49,7 @@ class AbstractReader { */ byGlob(virPattern, options = {nodir: true}) { const trace = new Trace(virPattern); - return this._byGlob(virPattern, options, trace).then(function(result) { + return this._byGlob(virPattern, options, trace).then(function (result) { trace.printReport(); return result; }).then((resources) => { @@ -59,7 +59,7 @@ class AbstractReader { const x = 0; const y = randomInt(0, resources.length - 1); // Swap object at index "x" with "y" - resources[x] = [resources[y], resources[y]=resources[x]][0]; + resources[x] = [resources[y], resources[y] = resources[x]][0]; } return resources; }); @@ -76,7 +76,7 @@ class AbstractReader { */ byPath(virPath, options = {nodir: true}) { const trace = new Trace(virPath); - return this._byPath(virPath, options, trace).then(function(resource) { + return this._byPath(virPath, options, trace).then(function (resource) { trace.printReport(); return resource; }); diff --git a/src/DuplexCollection.ts b/src/DuplexCollection.ts index 6aec0ec7..df2b2672 100644 --- a/src/DuplexCollection.ts +++ b/src/DuplexCollection.ts @@ -36,8 +36,8 @@ class DuplexCollection extends AbstractReaderWriter { name: `${name} - ReaderCollectionPrioritized`, readers: [ writer, - reader - ] + reader, + ], }); } diff --git a/src/ReaderCollection.ts b/src/ReaderCollection.ts index f0fa9ffc..47432871 100644 --- a/src/ReaderCollection.ts +++ b/src/ReaderCollection.ts @@ -36,7 +36,7 @@ class ReaderCollection extends AbstractReader { * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ _byGlob(pattern, options, trace) { - return Promise.all(this._readers.map(function(resourceLocator) { + return Promise.all(this._readers.map(function (resourceLocator) { return resourceLocator._byGlob(pattern, options, trace); })).then((result) => { trace.collection(this._name); @@ -66,9 +66,9 @@ class ReaderCollection extends AbstractReader { } // Using Promise.race to deliver files that can be found as fast as possible - return Promise.race(this._readers.map(function(resourceLocator) { - return resourceLocator._byPath(virPath, options, trace).then(function(resource) { - return new Promise(function(resolve, reject) { + return Promise.race(this._readers.map(function (resourceLocator) { + return resourceLocator._byPath(virPath, options, trace).then(function (resource) { + return new Promise(function (resolve, reject) { trace.collection(that._name); resolveCount++; if (resource) { diff --git a/src/ReaderCollectionPrioritized.ts b/src/ReaderCollectionPrioritized.ts index 680b7135..17a35abe 100644 --- a/src/ReaderCollectionPrioritized.ts +++ b/src/ReaderCollectionPrioritized.ts @@ -36,7 +36,7 @@ class ReaderCollectionPrioritized extends AbstractReader { * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ _byGlob(pattern, options, trace) { - return Promise.all(this._readers.map(function(resourceLocator) { + return Promise.all(this._readers.map(function (resourceLocator) { return resourceLocator._byGlob(pattern, options, trace); })).then((result) => { const files = Object.create(null); diff --git a/src/Resource.ts b/src/Resource.ts index 0eb10b39..bcae1a32 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -63,7 +63,7 @@ class Resource { throw new Error("Unable to create Resource: Missing parameter 'path'"); } if (buffer && createStream || buffer && string || string && createStream || buffer && stream || - string && stream || createStream && stream) { + string && stream || createStream && stream) { throw new Error("Unable to create Resource: Please set only one content parameter. " + "'buffer', 'string', 'stream' or 'createStream'"); } @@ -73,7 +73,6 @@ class Resource { throw new Error(`Parameter 'sourceMetadata' must be of type "object"`); } - /* eslint-disable-next-line guard-for-in */ for (const metadataKey in sourceMetadata) { // Also check prototype if (!ALLOWED_SOURCE_METADATA_KEYS.includes(metadataKey)) { throw new Error(`Parameter 'sourceMetadata' contains an illegal attribute: ${metadataKey}`); @@ -115,7 +114,7 @@ class Resource { atime: new Date(), mtime: new Date(), ctime: new Date(), - birthtime: new Date() + birthtime: new Date(), }; if (createStream) { @@ -357,7 +356,7 @@ class Resource { const options = { path: this.#path, statInfo: clone(this.#statInfo), - sourceMetadata: clone(this.#sourceMetadata) + sourceMetadata: clone(this.#sourceMetadata), }; if (this.#stream) { diff --git a/src/ResourceFacade.ts b/src/ResourceFacade.ts index ef6dcdf8..07a0b10e 100644 --- a/src/ResourceFacade.ts +++ b/src/ResourceFacade.ts @@ -228,6 +228,7 @@ class ResourceFacade { hasProject() { return this.#resource.hasProject(); } + /** * Check whether the content of this resource has been changed during its life cycle * @@ -248,7 +249,6 @@ class ResourceFacade { return this.#resource.getSourceMetadata(); } - /** * Returns the resource concealed by this facade * diff --git a/src/WriterCollection.ts b/src/WriterCollection.ts index 7c01f783..cbcbc727 100644 --- a/src/WriterCollection.ts +++ b/src/WriterCollection.ts @@ -61,7 +61,7 @@ class WriterCollection extends AbstractReaderWriter { this._writerMapping = writerMapping; this._readerCollection = new ReaderCollection({ name: `Reader collection of writer collection '${this._name}'`, - readers: Object.values(writerMapping) + readers: Object.values(writerMapping), }); } diff --git a/src/adapters/AbstractAdapter.ts b/src/adapters/AbstractAdapter.ts index 96cf4154..a8c0cabd 100644 --- a/src/adapters/AbstractAdapter.ts +++ b/src/adapters/AbstractAdapter.ts @@ -48,6 +48,7 @@ class AbstractAdapter extends AbstractReaderWriter { this._excludesNegated = excludes.map((pattern) => `!${pattern}`); this._project = project; } + /** * Locates resources by glob. * @@ -83,15 +84,15 @@ class AbstractAdapter extends AbstractReaderWriter { return [ this._createResource({ statInfo: { // TODO: make closer to fs stat info - isDirectory: function() { + isDirectory: function () { return true; - } + }, }, source: { - adapter: "Abstract" + adapter: "Abstract", }, - path: subPath - }) + path: subPath, + }), ]; } } @@ -221,7 +222,7 @@ class AbstractAdapter extends AbstractReaderWriter { const options = { path: resource._path, statInfo: resource._statInfo, - source: resource._source + source: resource._source, }; if (resource._stream) { @@ -265,15 +266,15 @@ class AbstractAdapter extends AbstractReaderWriter { if (!this._isPathHandled(virPath)) { if (log.isLevelEnabled("silly")) { log.silly(`Failed to resolve virtual path '${inputVirPath}': ` + - `Resolved path does not start with adapter base path '${this._virBasePath}' or equals ` + - `base dir: ${this._virBaseDir}`); + `Resolved path does not start with adapter base path '${this._virBasePath}' or equals ` + + `base dir: ${this._virBaseDir}`); } return null; } if (this._isPathExcluded(virPath)) { if (log.isLevelEnabled("silly")) { log.silly(`Failed to resolve virtual path '${inputVirPath}': ` + - `Resolved path is excluded by configuration of adapter with base path '${this._virBasePath}'`); + `Resolved path is excluded by configuration of adapter with base path '${this._virBasePath}'`); } return null; } diff --git a/src/adapters/FileSystem.ts b/src/adapters/FileSystem.ts index f7862caa..ff99873d 100644 --- a/src/adapters/FileSystem.ts +++ b/src/adapters/FileSystem.ts @@ -35,7 +35,7 @@ class FileSystem extends AbstractAdapter { * Whether to apply any excludes defined in an optional .gitignore in the given fsBasePath directory * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) */ - constructor({virBasePath, project, fsBasePath, excludes, useGitignore=false}) { + constructor({virBasePath, project, fsBasePath, excludes, useGitignore = false}) { super({virBasePath, project, excludes}); if (!fsBasePath) { @@ -81,11 +81,11 @@ class FileSystem extends AbstractAdapter { path: this._virBaseDir, sourceMetadata: { adapter: ADAPTER_NAME, - fsPath: this._fsBasePath + fsPath: this._fsBasePath, }, createStream: () => { return fs.createReadStream(this._fsBasePath); - } + }, })); } }); @@ -125,11 +125,11 @@ class FileSystem extends AbstractAdapter { path: virPath, sourceMetadata: { adapter: ADAPTER_NAME, - fsPath: fsPath + fsPath: fsPath, }, createStream: () => { return fs.createReadStream(fsPath); - } + }, })); } }); @@ -162,11 +162,11 @@ class FileSystem extends AbstractAdapter { return this._createResource({ project: this._project, statInfo: { // TODO: make closer to fs stat info - isDirectory: function() { + isDirectory: function () { return true; - } + }, }, - path: virPath + path: virPath, }); } else { return null; @@ -180,7 +180,7 @@ class FileSystem extends AbstractAdapter { if (this._useGitignore) { if (!this._isGitIgnored) { this._isGitIgnored = await isGitIgnored({ - cwd: this._fsBasePath + cwd: this._fsBasePath, }); } // Check whether path should be ignored @@ -201,13 +201,13 @@ class FileSystem extends AbstractAdapter { path: virPath, sourceMetadata: { adapter: ADAPTER_NAME, - fsPath - } + fsPath, + }, }; if (!statInfo.isDirectory()) { // Add content as lazy stream - resourceOptions.createStream = function() { + resourceOptions.createStream = function () { return fs.createReadStream(fsPath); }; } @@ -347,7 +347,7 @@ class FileSystem extends AbstractAdapter { // This should be identical to buffering the resource content in memory, since the written file // can not be modified. // We chose this approach to be more memory efficient in scenarios where readOnly is used - resource.setStream(function() { + resource.setStream(function () { return fs.createReadStream(fsPath); }); } diff --git a/src/adapters/Memory.ts b/src/adapters/Memory.ts index 35be99cf..7711b2c4 100644 --- a/src/adapters/Memory.ts +++ b/src/adapters/Memory.ts @@ -41,7 +41,7 @@ class Memory extends AbstractAdapter { async _matchPatterns(patterns, resourceMap) { const resourcePaths = Object.keys(resourceMap); const matchedPaths = micromatch(resourcePaths, patterns, { - dot: true + dot: true, }); return await Promise.all(matchedPaths.map((virPath) => { const resource = resourceMap[virPath]; @@ -75,15 +75,15 @@ class Memory extends AbstractAdapter { this._createResource({ project: this._project, statInfo: { // TODO: make closer to fs stat info - isDirectory: function() { + isDirectory: function () { return true; - } + }, }, sourceMetadata: { - adapter: ADAPTER_NAME + adapter: ADAPTER_NAME, }, - path: this._virBasePath.slice(0, -1) - }) + path: this._virBasePath.slice(0, -1), + }), ]; } @@ -160,14 +160,14 @@ class Memory extends AbstractAdapter { this._virDirs[segment] = this._createResource({ project: this._project, sourceMetadata: { - adapter: ADAPTER_NAME + adapter: ADAPTER_NAME, }, statInfo: { // TODO: make closer to fs stat info - isDirectory: function() { + isDirectory: function () { return true; - } + }, }, - path: this._virBasePath + segment + path: this._virBasePath + segment, }); } } diff --git a/src/fsInterface.ts b/src/fsInterface.ts index 99d97712..fa814122 100644 --- a/src/fsInterface.ts +++ b/src/fsInterface.ts @@ -33,8 +33,8 @@ function fsInterface(reader) { } const posixPath = toPosix(fsPath); reader.byPath(posixPath, { - nodir: false - }).then(function(resource) { + nodir: false, + }).then(function (resource) { if (!resource) { const error = new Error(`ENOENT: no such file or directory, open '${fsPath}'`); error.code = "ENOENT"; // "File or directory does not exist" @@ -42,10 +42,10 @@ function fsInterface(reader) { return; } - return resource.getBuffer().then(function(buffer) { + return resource.getBuffer().then(function (buffer) { let res; - if (options && options.encoding) { + if (options?.encoding) { res = buffer.toString(options.encoding); } else { res = buffer; @@ -58,8 +58,8 @@ function fsInterface(reader) { stat(fsPath, callback) { const posixPath = toPosix(fsPath); reader.byPath(posixPath, { - nodir: false - }).then(function(resource) { + nodir: false, + }).then(function (resource) { if (!resource) { const error = new Error(`ENOENT: no such file or directory, stat '${fsPath}'`); error.code = "ENOENT"; // "File or directory does not exist" @@ -76,7 +76,7 @@ function fsInterface(reader) { posixPath += "/"; } reader.byGlob(posixPath + "*", { - nodir: false + nodir: false, }).then((resources) => { const files = resources.map((resource) => { return resource.getName(); @@ -86,7 +86,7 @@ function fsInterface(reader) { }, mkdir(fsPath, callback) { setTimeout(callback, 0); - } + }, }; } export default fsInterface; diff --git a/src/readers/Link.ts b/src/readers/Link.ts index dd2d40b3..8ba0b089 100644 --- a/src/readers/Link.ts +++ b/src/readers/Link.ts @@ -88,7 +88,7 @@ class Link extends AbstractReader { if (resourcePath.startsWith(this._pathMapping.targetPath)) { return new ResourceFacade({ resource, - path: this._pathMapping.linkPath + resourcePath.substr(this._pathMapping.targetPath.length) + path: this._pathMapping.linkPath + resourcePath.substr(this._pathMapping.targetPath.length), }); } }); @@ -114,7 +114,7 @@ class Link extends AbstractReader { if (resource) { return new ResourceFacade({ resource, - path: this._pathMapping.linkPath + resource.getPath().substr(this._pathMapping.targetPath.length) + path: this._pathMapping.linkPath + resource.getPath().substr(this._pathMapping.targetPath.length), }); } return null; diff --git a/src/resourceFactory.ts b/src/resourceFactory.ts index ba48d76d..611e450a 100644 --- a/src/resourceFactory.ts +++ b/src/resourceFactory.ts @@ -84,7 +84,7 @@ export function createReader({fsBasePath, virBasePath, project, excludes = [], n // Flatten list of patterns normalizedExcludes = Array.prototype.concat.apply([], normalizedExcludes); log.verbose(`Effective exclude patterns for application project ${project.getName()}:\n` + - normalizedExcludes.join(", ")); + normalizedExcludes.join(", ")); } return new ReaderCollection({ name, @@ -92,8 +92,8 @@ export function createReader({fsBasePath, virBasePath, project, excludes = [], n fsBasePath, virBasePath, project, - excludes: normalizedExcludes - })] + excludes: normalizedExcludes, + })], }); } @@ -109,7 +109,7 @@ export function createReader({fsBasePath, virBasePath, project, excludes = [], n export function createReaderCollection({name, readers}) { return new ReaderCollection({ name, - readers + readers, }); } @@ -126,7 +126,7 @@ export function createReaderCollection({name, readers}) { export function createReaderCollectionPrioritized({name, readers}) { return new ReaderCollectionPrioritized({ name, - readers + readers, }); } @@ -143,7 +143,7 @@ export function createReaderCollectionPrioritized({name, readers}) { export function createWriterCollection({name, writerMapping}) { return new WriterCollection({ name, - writerMapping + writerMapping, }); } @@ -178,14 +178,14 @@ export function createResource(parameters) { export function createWorkspace({reader, writer, virBasePath = "/", name = "workspace"}) { if (!writer) { writer = new MemAdapter({ - virBasePath + virBasePath, }); } return new DuplexCollection({ reader, writer, - name + name, }); } @@ -251,8 +251,8 @@ export function createFlatReader({reader, namespace}) { reader: reader, pathMapping: { linkPath: `/`, - targetPath: `/resources/${namespace}/` - } + targetPath: `/resources/${namespace}/`, + }, }); } diff --git a/src/tracing/Trace.ts b/src/tracing/Trace.ts index 30ac9e19..a6835be9 100644 --- a/src/tracing/Trace.ts +++ b/src/tracing/Trace.ts @@ -50,7 +50,7 @@ class Trace { this._collections[name].calls++; } else { this._collections[name] = { - calls: 1 + calls: 1, }; } summaryTrace.collection(name); diff --git a/src/tracing/traceSummary.ts b/src/tracing/traceSummary.ts index 79f89378..54755515 100644 --- a/src/tracing/traceSummary.ts +++ b/src/tracing/traceSummary.ts @@ -14,7 +14,7 @@ function init() { pathCalls: 0, globCalls: 0, collections: {}, - traceCalls: 0 + traceCalls: 0, }; active = true; } @@ -65,7 +65,7 @@ function someTraceStarted() { } function someTraceEnded() { - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { if (!active) { resolve(); return; @@ -80,7 +80,7 @@ function someTraceEnded() { clearTimeout(timeoutId); } traceData.timeDiff = process.hrtime(traceData.startTime); - timeoutId = setTimeout(function() { + timeoutId = setTimeout(function () { report(); reset(); resolve(); @@ -111,7 +111,7 @@ function collection(name) { traceData.collections[name].calls++; } else { traceData.collections[name] = { - calls: 1 + calls: 1, }; } } @@ -121,5 +121,5 @@ export default { globCall: globCall, collection: collection, traceStarted: someTraceStarted, - traceEnded: someTraceEnded + traceEnded: someTraceEnded, }; diff --git a/test/lib/AbstractReader.ts b/test/lib/AbstractReader.ts index c5d9c009..db5bf308 100644 --- a/test/lib/AbstractReader.ts +++ b/test/lib/AbstractReader.ts @@ -6,7 +6,7 @@ test("AbstractReader: constructor throws an error", (t) => { new AbstractReader(); }, { instanceOf: TypeError, - message: "Class 'AbstractReader' is abstract" + message: "Class 'AbstractReader' is abstract", }); }); @@ -18,20 +18,20 @@ test("Incomplete AbstractReader subclass: Abstract functions throw error", (t) = instance._byGlob(); }, { instanceOf: Error, - message: "Function '_byGlob' is not implemented" + message: "Function '_byGlob' is not implemented", }); t.throws(() => { instance._runGlob(); }, { instanceOf: Error, - message: "Function '_runGlob' is not implemented" + message: "Function '_runGlob' is not implemented", }); t.throws(() => { instance._byPath(); }, { instanceOf: Error, - message: "Function '_byPath' is not implemented" + message: "Function '_byPath' is not implemented", }); }); diff --git a/test/lib/AbstractReaderWriter.ts b/test/lib/AbstractReaderWriter.ts index 1cb5cec2..768b0c85 100644 --- a/test/lib/AbstractReaderWriter.ts +++ b/test/lib/AbstractReaderWriter.ts @@ -6,7 +6,7 @@ test("AbstractReaderWriter: constructor throws an error", (t) => { new AbstractReaderWriter(); }, { instanceOf: TypeError, - message: "Class 'AbstractReaderWriter' is abstract" + message: "Class 'AbstractReaderWriter' is abstract", }); }); @@ -19,7 +19,6 @@ test("Incomplete AbstractReaderWriter subclass: Abstract functions throw error", instance._write(); }, { instanceOf: Error, - message: "Not implemented" + message: "Not implemented", }); }); - diff --git a/test/lib/DuplexCollection.ts b/test/lib/DuplexCollection.ts index bba5b096..3ec97ebb 100644 --- a/test/lib/DuplexCollection.ts +++ b/test/lib/DuplexCollection.ts @@ -8,7 +8,7 @@ test("DuplexCollection: constructor", (t) => { const duplexCollection = new DuplexCollection({ name: "myCollection", reader: {}, - writer: {} + writer: {}, }); t.deepEqual(duplexCollection._reader, {}, "reader assigned"); @@ -21,7 +21,7 @@ test("DuplexCollection: constructor", (t) => { test("DuplexCollection: constructor with setting default name of an empty string", (t) => { const duplexCollection = new DuplexCollection({ reader: {}, - writer: {} + writer: {}, }); t.deepEqual(duplexCollection._reader, {}, "reader assigned"); @@ -35,15 +35,15 @@ test("DuplexCollection: _byGlob w/o finding a resource", async (t) => { t.plan(3); const abstractReader = { - _byGlob: sinon.stub().returns(Promise.resolve([])) + _byGlob: sinon.stub().returns(Promise.resolve([])), }; const duplexCollection = new DuplexCollection({ name: "myCollection", reader: abstractReader, - writer: abstractReader + writer: abstractReader, }); const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const comboSpy = sinon.spy(duplexCollection._combo, "_byGlob"); @@ -60,18 +60,18 @@ test("DuplexCollection: _byGlob", async (t) => { const resource = new Resource({ path: "/my/path", - buffer: Buffer.from("content") + buffer: Buffer.from("content"), }); const abstractReader = { - _byGlob: sinon.stub().returns(Promise.resolve([resource])) + _byGlob: sinon.stub().returns(Promise.resolve([resource])), }; const duplexCollection = new DuplexCollection({ name: "myCollection", reader: abstractReader, - writer: abstractReader + writer: abstractReader, }); const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const comboSpy = sinon.spy(duplexCollection._combo, "_byGlob"); const resources = await duplexCollection._byGlob("anyPattern", {someOption: true}, trace); @@ -90,19 +90,19 @@ test("DuplexCollection: _byPath with reader finding a resource", async (t) => { const resource = new Resource({ path: "/path", - buffer: Buffer.from("content") + buffer: Buffer.from("content"), }); const pushCollectionSpy = sinon.spy(resource, "pushCollection"); const abstractReader = { - _byPath: sinon.stub().returns(Promise.resolve(resource)) + _byPath: sinon.stub().returns(Promise.resolve(resource)), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const duplexCollection = new DuplexCollection({ name: "myCollection", reader: abstractReader, - writer: abstractReader + writer: abstractReader, }); const comboSpy = sinon.spy(duplexCollection._combo, "_byPath"); const readResource = await duplexCollection._byPath("anyVirtualPath", {someOption: true}, trace); @@ -119,18 +119,18 @@ test("DuplexCollection: _byPath with two readers both finding no resource", asyn t.plan(3); const abstractReaderOne = { - _byPath: sinon.stub().returns(Promise.resolve()) + _byPath: sinon.stub().returns(Promise.resolve()), }; const abstractReaderTwo = { - _byPath: sinon.stub().returns(Promise.resolve()) + _byPath: sinon.stub().returns(Promise.resolve()), }; const trace = { - collection: sinon.stub() + collection: sinon.stub(), }; const duplexCollection = new DuplexCollection({ name: "myCollection", reader: abstractReaderOne, - writer: abstractReaderTwo + writer: abstractReaderTwo, }); const readResource = await duplexCollection._byPath("anyVirtualPath", {someOption: true}, trace); @@ -146,14 +146,14 @@ test("DuplexCollection: _write successful", async (t) => { const resource = new Resource({ path: "/my/path", - buffer: Buffer.from("content") + buffer: Buffer.from("content"), }); const duplexCollection = new DuplexCollection({ name: "myCollection", reader: {}, writer: { - write: sinon.stub().returns(Promise.resolve()) - } + write: sinon.stub().returns(Promise.resolve()), + }, }); await duplexCollection._write(resource); @@ -164,10 +164,10 @@ test("DuplexCollection: Throws for empty reader", (t) => { t.throws(() => { new DuplexCollection({ name: "myReader", - writer: {} + writer: {}, }); }, { - message: "Cannot create DuplexCollection myReader: No reader provided" + message: "Cannot create DuplexCollection myReader: No reader provided", }); }); @@ -175,9 +175,9 @@ test("DuplexCollection: Throws for empty writer", (t) => { t.throws(() => { new DuplexCollection({ name: "myReader", - reader: {} + reader: {}, }); }, { - message: "Cannot create DuplexCollection myReader: No writer provided" + message: "Cannot create DuplexCollection myReader: No writer provided", }); }); diff --git a/test/lib/ReaderCollection.ts b/test/lib/ReaderCollection.ts index d808591b..8edbc0c6 100644 --- a/test/lib/ReaderCollection.ts +++ b/test/lib/ReaderCollection.ts @@ -6,7 +6,7 @@ import Resource from "../../lib/Resource.js"; test("ReaderCollection: constructor", (t) => { const readerCollection = new ReaderCollection({ name: "myReader", - readers: [{}, {}, {}] + readers: [{}, {}, {}], }); t.is(readerCollection.getName(), "myReader", "correct name assigned"); @@ -17,14 +17,14 @@ test("ReaderCollection: _byGlob w/o finding a resource", async (t) => { t.plan(4); const abstractReader = { - _byGlob: sinon.stub().returns(Promise.resolve([])) + _byGlob: sinon.stub().returns(Promise.resolve([])), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new ReaderCollection({ name: "myReader", - readers: [abstractReader] + readers: [abstractReader], }); const resources = await readerCollection._byGlob("anyPattern", {someOption: true}, trace); @@ -40,17 +40,17 @@ test("ReaderCollection: _byGlob with finding a resource", async (t) => { const resource = new Resource({ path: "/my/path", - buffer: Buffer.from("content") + buffer: Buffer.from("content"), }); const abstractReader = { - _byGlob: sinon.stub().returns(Promise.resolve([resource])) + _byGlob: sinon.stub().returns(Promise.resolve([resource])), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new ReaderCollection({ name: "myReader", - readers: [abstractReader] + readers: [abstractReader], }); const resources = await readerCollection._byGlob("anyPattern", {someOption: true}, trace); @@ -70,18 +70,18 @@ test("ReaderCollection: _byPath with reader finding a resource", async (t) => { const resource = new Resource({ path: "/my/path", - buffer: Buffer.from("content") + buffer: Buffer.from("content"), }); const pushCollectionSpy = sinon.spy(resource, "pushCollection"); const abstractReader = { - _byPath: sinon.stub().returns(Promise.resolve(resource)) + _byPath: sinon.stub().returns(Promise.resolve(resource)), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new ReaderCollection({ name: "myReader", - readers: [abstractReader] + readers: [abstractReader], }); const readResource = await readerCollection._byPath("anyVirtualPath", {someOption: true}, trace); @@ -99,17 +99,17 @@ test("ReaderCollection: _byPath with two readers both finding no resource", asyn t.plan(4); const abstractReaderOne = { - _byPath: sinon.stub().returns(Promise.resolve()) + _byPath: sinon.stub().returns(Promise.resolve()), }; const abstractReaderTwo = { - _byPath: sinon.stub().returns(Promise.resolve()) + _byPath: sinon.stub().returns(Promise.resolve()), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new ReaderCollection({ name: "myReader", - readers: [abstractReaderOne, abstractReaderTwo] + readers: [abstractReaderOne, abstractReaderTwo], }); const resource = await readerCollection._byPath("anyVirtualPath", {someOption: true}, trace); @@ -124,11 +124,11 @@ test("ReaderCollection: _byPath with two readers both finding no resource", asyn test("ReaderCollection: _byPath with empty readers array", async (t) => { const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new ReaderCollection({ name: "myReader", - readers: [] + readers: [], }); const resource = await readerCollection._byPath("anyVirtualPath", {someOption: true}, trace); @@ -138,21 +138,21 @@ test("ReaderCollection: _byPath with empty readers array", async (t) => { test("ReaderCollection: _byPath with some empty readers", async (t) => { const resource = new Resource({ path: "/my/path", - buffer: Buffer.from("content") + buffer: Buffer.from("content"), }); const abstractReaderOne = { - _byPath: sinon.stub().resolves(resource) + _byPath: sinon.stub().resolves(resource), }; const abstractReaderTwo = { - _byPath: sinon.stub().resolves() + _byPath: sinon.stub().resolves(), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new ReaderCollection({ name: "myReader", - readers: [abstractReaderOne, undefined, abstractReaderTwo] + readers: [abstractReaderOne, undefined, abstractReaderTwo], }); const res = await readerCollection._byPath("anyVirtualPath", {someOption: true}, trace); @@ -161,11 +161,11 @@ test("ReaderCollection: _byPath with some empty readers", async (t) => { test("ReaderCollection: _byGlob with empty readers array", async (t) => { const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new ReaderCollection({ name: "myReader", - readers: [] + readers: [], }); const resource = await readerCollection.byGlob("anyPattern", {someOption: true}, trace); @@ -175,21 +175,21 @@ test("ReaderCollection: _byGlob with empty readers array", async (t) => { test("ReaderCollection: _byGlob with some empty readers", async (t) => { const resource = new Resource({ path: "/my/path", - buffer: Buffer.from("content") + buffer: Buffer.from("content"), }); const abstractReaderOne = { - _byGlob: sinon.stub().resolves([resource]) + _byGlob: sinon.stub().resolves([resource]), }; const abstractReaderTwo = { - _byGlob: sinon.stub().resolves([]) + _byGlob: sinon.stub().resolves([]), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new ReaderCollection({ name: "myReader", - readers: [abstractReaderOne, undefined, abstractReaderTwo] + readers: [abstractReaderOne, undefined, abstractReaderTwo], }); const res = await readerCollection._byGlob("anyVirtualPath", {someOption: true}, trace); diff --git a/test/lib/ReaderCollectionPrioritized.ts b/test/lib/ReaderCollectionPrioritized.ts index e13cda12..a0579a73 100644 --- a/test/lib/ReaderCollectionPrioritized.ts +++ b/test/lib/ReaderCollectionPrioritized.ts @@ -6,7 +6,7 @@ import Resource from "../../lib/Resource.js"; test("ReaderCollectionPrioritized: constructor", (t) => { const readerCollectionPrioritized = new ReaderCollectionPrioritized({ name: "myReader", - readers: [{}, {}, {}] + readers: [{}, {}, {}], }); t.is(readerCollectionPrioritized.getName(), "myReader", "correct name assigned"); @@ -15,14 +15,14 @@ test("ReaderCollectionPrioritized: constructor", (t) => { test("ReaderCollectionPrioritized: _byGlob w/o finding a resource", async (t) => { const abstractReader = { - _byGlob: sinon.stub().returns(Promise.resolve([])) + _byGlob: sinon.stub().returns(Promise.resolve([])), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollectionPrioritized = new ReaderCollectionPrioritized({ name: "myReader", - readers: [abstractReader] + readers: [abstractReader], }); const resources = await readerCollectionPrioritized._byGlob("anyPattern", {someOption: true}, trace); @@ -36,17 +36,17 @@ test("ReaderCollectionPrioritized: _byGlob w/o finding a resource", async (t) => test("ReaderCollectionPrioritized: _byGlob with finding a resource", async (t) => { const resource = new Resource({ path: "/my/path", - buffer: Buffer.from("content") + buffer: Buffer.from("content"), }); const abstractReader = { - _byGlob: sinon.stub().returns(Promise.resolve([resource])) + _byGlob: sinon.stub().returns(Promise.resolve([resource])), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollectionPrioritized = new ReaderCollectionPrioritized({ name: "myReader", - readers: [abstractReader] + readers: [abstractReader], }); const resources = await readerCollectionPrioritized._byGlob("anyPattern", {someOption: true}, trace); @@ -64,18 +64,18 @@ test("ReaderCollectionPrioritized: _byGlob with finding a resource", async (t) = test("ReaderCollectionPrioritized: _byPath with reader finding a resource", async (t) => { const resource = new Resource({ path: "/my/path", - buffer: Buffer.from("content") + buffer: Buffer.from("content"), }); const pushCollectionSpy = sinon.spy(resource, "pushCollection"); const abstractReader = { - _byPath: sinon.stub().returns(Promise.resolve(resource)) + _byPath: sinon.stub().returns(Promise.resolve(resource)), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollectionPrioritized = new ReaderCollectionPrioritized({ name: "myReader", - readers: [abstractReader] + readers: [abstractReader], }); const readResource = await readerCollectionPrioritized._byPath("anyVirtualPath", {someOption: true}, trace); @@ -90,17 +90,17 @@ test("ReaderCollectionPrioritized: _byPath with reader finding a resource", asyn test("ReaderCollectionPrioritized: _byPath with two readers both finding no resource", async (t) => { const abstractReaderOne = { - _byPath: sinon.stub().returns(Promise.resolve()) + _byPath: sinon.stub().returns(Promise.resolve()), }; const abstractReaderTwo = { - _byPath: sinon.stub().returns(Promise.resolve()) + _byPath: sinon.stub().returns(Promise.resolve()), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollectionPrioritized = new ReaderCollectionPrioritized({ name: "myReader", - readers: [abstractReaderOne, abstractReaderTwo] + readers: [abstractReaderOne, abstractReaderTwo], }); const resource = await readerCollectionPrioritized._byPath("anyVirtualPath", {someOption: true}, trace); @@ -114,11 +114,11 @@ test("ReaderCollectionPrioritized: _byPath with two readers both finding no reso test("ReaderCollectionPrioritized: _byPath with empty readers array", async (t) => { const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollectionPrioritized = new ReaderCollectionPrioritized({ name: "myReader", - readers: [] + readers: [], }); const resource = await readerCollectionPrioritized._byPath("anyVirtualPath", {someOption: true}, trace); @@ -128,21 +128,21 @@ test("ReaderCollectionPrioritized: _byPath with empty readers array", async (t) test("ReaderCollectionPrioritized: _byPath with some empty readers", async (t) => { const resource = new Resource({ path: "/my/path", - buffer: Buffer.from("content") + buffer: Buffer.from("content"), }); const abstractReaderOne = { - _byPath: sinon.stub().resolves(resource) + _byPath: sinon.stub().resolves(resource), }; const abstractReaderTwo = { - _byPath: sinon.stub().resolves() + _byPath: sinon.stub().resolves(), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollectionPrioritized = new ReaderCollectionPrioritized({ name: "myReader", - readers: [abstractReaderOne, undefined, abstractReaderTwo] + readers: [abstractReaderOne, undefined, abstractReaderTwo], }); const res = await readerCollectionPrioritized._byPath("anyVirtualPath", {someOption: true}, trace); @@ -151,11 +151,11 @@ test("ReaderCollectionPrioritized: _byPath with some empty readers", async (t) = test("ReaderCollectionPrioritized: _byGlob with empty readers array", async (t) => { const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollectionPrioritized = new ReaderCollectionPrioritized({ name: "myReader", - readers: [] + readers: [], }); const resource = await readerCollectionPrioritized.byGlob("anyPattern", {someOption: true}, trace); @@ -165,21 +165,21 @@ test("ReaderCollectionPrioritized: _byGlob with empty readers array", async (t) test("ReaderCollectionPrioritized: _byGlob with some empty readers", async (t) => { const resource = new Resource({ path: "/my/path", - buffer: Buffer.from("content") + buffer: Buffer.from("content"), }); const abstractReaderOne = { - _byGlob: sinon.stub().resolves([resource]) + _byGlob: sinon.stub().resolves([resource]), }; const abstractReaderTwo = { - _byGlob: sinon.stub().resolves([]) + _byGlob: sinon.stub().resolves([]), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollectionPrioritized = new ReaderCollectionPrioritized({ name: "myReader", - readers: [abstractReaderOne, undefined, abstractReaderTwo] + readers: [abstractReaderOne, undefined, abstractReaderTwo], }); const res = await readerCollectionPrioritized._byGlob("anyVirtualPath", {someOption: true}, trace); diff --git a/test/lib/Resource.ts b/test/lib/Resource.ts index aca04728..f33a2878 100644 --- a/test/lib/Resource.ts +++ b/test/lib/Resource.ts @@ -8,12 +8,12 @@ function createBasicResource() { const fsPath = path.join("test", "fixtures", "application.a", "webapp", "index.html"); const resource = new Resource({ path: "/app/index.html", - createStream: function() { + createStream: function () { return createReadStream(fsPath); }, project: {}, statInfo: {}, - fsPath + fsPath, }); return resource; } @@ -44,7 +44,7 @@ test("Resource: constructor with missing path parameter", (t) => { new Resource({}); }, { instanceOf: Error, - message: "Unable to create Resource: Missing parameter 'path'" + message: "Unable to create Resource: Missing parameter 'path'", }); }); @@ -86,7 +86,7 @@ test("Resource: constructor with duplicated content parameter", (t) => { }, { instanceOf: Error, message: "Unable to create Resource: Please set only one content parameter. " + - "'buffer', 'string', 'stream' or 'createStream'" + "'buffer', 'string', 'stream' or 'createStream'", }, "Threw with expected error message"); }); }); @@ -94,7 +94,7 @@ test("Resource: constructor with duplicated content parameter", (t) => { test("Resource: From buffer", async (t) => { const resource = new Resource({ path: "/my/path", - buffer: Buffer.from("Content") + buffer: Buffer.from("Content"), }); t.is(await resource.getSize(), 7, "Content is set"); t.false(resource.isModified(), "Content of new resource is not modified"); @@ -104,7 +104,7 @@ test("Resource: From buffer", async (t) => { test("Resource: From string", async (t) => { const resource = new Resource({ path: "/my/path", - string: "Content" + string: "Content", }); t.is(await resource.getSize(), 7, "Content is set"); t.false(resource.isModified(), "Content of new resource is not modified"); @@ -115,7 +115,7 @@ test("Resource: From stream", async (t) => { const fsPath = path.join("test", "fixtures", "application.a", "webapp", "index.html"); const resource = new Resource({ path: "/my/path", - stream: createReadStream(fsPath) + stream: createReadStream(fsPath), }); t.is(await resource.getSize(), 91, "Content is set"); t.false(resource.isModified(), "Content of new resource is not modified"); @@ -128,7 +128,7 @@ test("Resource: From createStream", async (t) => { path: "/my/path", createStream: () => { return createReadStream(fsPath); - } + }, }); t.is(await resource.getSize(), 91, "Content is set"); t.false(resource.isModified(), "Content of new resource is not modified"); @@ -141,8 +141,8 @@ test("Resource: Source metadata", async (t) => { string: "Content", sourceMetadata: { adapter: "My Adapter", - fsPath: "/some/path" - } + fsPath: "/some/path", + }, }); t.is(await resource.getSize(), 7, "Content is set"); t.false(resource.isModified(), "Content of new resource is not modified"); @@ -157,8 +157,8 @@ test("Resource: Source metadata with modified content", async (t) => { sourceMetadata: { adapter: "My Adapter", fsPath: "/some/path", - contentModified: true - } + contentModified: true, + }, }); t.is(await resource.getSize(), 7, "Content is set"); t.false(resource.isModified(), "Content of new resource is not modified"); @@ -175,11 +175,11 @@ test("Resource: Illegal source metadata attribute", (t) => { sourceMetadata: { adapter: "My Adapter", fsPath: "/some/path", - pony: "🦄" - } + pony: "🦄", + }, }); }, { - message: `Parameter 'sourceMetadata' contains an illegal attribute: pony` + message: `Parameter 'sourceMetadata' contains an illegal attribute: pony`, }, "Threw with expected error message"); }); @@ -191,12 +191,12 @@ test("Resource: Illegal source metadata value", (t) => { sourceMetadata: { adapter: "My Adapter", fsPath: { - some: "value" - } - } + some: "value", + }, + }, }); }, { - message: `Attribute 'fsPath' of parameter 'sourceMetadata' must be of type "string" or "boolean"` + message: `Attribute 'fsPath' of parameter 'sourceMetadata' must be of type "string" or "boolean"`, }, "Threw with expected error message"); }); @@ -207,7 +207,7 @@ test("Resource: getBuffer with throwing an error", (t) => { path: "/my/path/to/resource", }); - return resource.getBuffer().catch(function(error) { + return resource.getBuffer().catch(function (error) { t.is(error.message, "Resource /my/path/to/resource has no content", "getBuffer called w/o having a resource content provided"); }); @@ -216,7 +216,7 @@ test("Resource: getBuffer with throwing an error", (t) => { test("Resource: getPath / getName", (t) => { const resource = new Resource({ path: "/my/path/to/resource.js", - buffer: Buffer.from("Content") + buffer: Buffer.from("Content"), }); t.is(resource.getPath(), "/my/path/to/resource.js", "Correct path"); t.is(resource.getName(), "resource.js", "Correct name"); @@ -225,7 +225,7 @@ test("Resource: getPath / getName", (t) => { test("Resource: setPath / getName", (t) => { const resource = new Resource({ path: "/my/path/to/resource.js", - buffer: Buffer.from("Content") + buffer: Buffer.from("Content"), }); resource.setPath("/my/other/file.json"); t.is(resource.getPath(), "/my/other/file.json", "Correct path"); @@ -235,12 +235,12 @@ test("Resource: setPath / getName", (t) => { test("Resource: setPath with non-absolute path", (t) => { const resource = new Resource({ path: "/my/path/to/resource.js", - buffer: Buffer.from("Content") + buffer: Buffer.from("Content"), }); t.throws(() => { resource.setPath("my/other/file.json"); }, { - message: "Unable to set resource path: Path must be absolute: my/other/file.json" + message: "Unable to set resource path: Path must be absolute: my/other/file.json", }, "Threw with expected error message"); t.is(resource.getPath(), "/my/path/to/resource.js", "Path is unchanged"); t.is(resource.getName(), "resource.js", "Name is unchanged"); @@ -250,10 +250,10 @@ test("Create Resource with non-absolute path", (t) => { t.throws(() => { new Resource({ path: "my/path/to/resource.js", - buffer: Buffer.from("Content") + buffer: Buffer.from("Content"), }); }, { - message: "Unable to set resource path: Path must be absolute: my/path/to/resource.js" + message: "Unable to set resource path: Path must be absolute: my/path/to/resource.js", }, "Threw with expected error message"); }); @@ -262,7 +262,7 @@ test("Resource: getStream", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", - buffer: Buffer.from("Content") + buffer: Buffer.from("Content"), }); const result = await readStream(resource.getStream()); @@ -274,7 +274,7 @@ test("Resource: getStream for empty string", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", - string: "" + string: "", }); const result = await readStream(resource.getStream()); @@ -286,8 +286,8 @@ test("Resource: getStream for empty string instance", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", - // eslint-disable-next-line no-new-wrappers - string: new String("") + + string: new String(""), }); const result = await readStream(resource.getStream()); @@ -296,21 +296,21 @@ test("Resource: getStream for empty string instance", async (t) => { test("Resource: getStream throwing an error", (t) => { const resource = new Resource({ - path: "/my/path/to/resource" + path: "/my/path/to/resource", }); t.throws(() => { resource.getStream(); }, { instanceOf: Error, - message: "Resource /my/path/to/resource has no content" + message: "Resource /my/path/to/resource has no content", }); }); test("Resource: setString", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", - sourceMetadata: {} // Needs to be passed in order to get the "modified" state + sourceMetadata: {}, // Needs to be passed in order to get the "modified" state }); t.is(resource.getSourceMetadata().contentModified, false, "sourceMetadata modified flag set correctly"); @@ -328,7 +328,7 @@ test("Resource: setString", async (t) => { test("Resource: setBuffer", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", - sourceMetadata: {} // Needs to be passed in order to get the "modified" state + sourceMetadata: {}, // Needs to be passed in order to get the "modified" state }); t.is(resource.getSourceMetadata().contentModified, false, "sourceMetadata modified flag set correctly"); @@ -345,7 +345,7 @@ test("Resource: setBuffer", async (t) => { test("Resource: size modification", async (t) => { const resource = new Resource({ - path: "/my/path/to/resource" + path: "/my/path/to/resource", }); t.is(await resource.getSize(), 0, "initial size without content"); @@ -355,7 +355,7 @@ test("Resource: size modification", async (t) => { t.is(await resource.getSize(), 7, "size after manually setting the string"); t.is(await new Resource({ path: "/my/path/to/resource", - string: "Content" + string: "Content", }).getSize(), 7, "size when passing string to constructor"); // buffer @@ -374,7 +374,7 @@ test("Resource: size modification", async (t) => { t.is(await resource.getSize(), 1234, "buffer with alloc after setting the buffer"); t.is(await new Resource({ path: "/my/path/to/resource", - buffer: buf + buffer: buf, }).getSize(), 1234, "buffer with alloc when passing buffer to constructor"); const clonedResource2 = await resource.clone(); @@ -385,7 +385,7 @@ test("Resource: size modification", async (t) => { path: "/my/path/to/resource", }); const stream = new Stream.Readable(); - stream._read = function() {}; + stream._read = function () {}; stream.push("I am a "); stream.push("readable "); stream.push("stream!"); @@ -404,14 +404,14 @@ test("Resource: size modification", async (t) => { test("Resource: setStream (Stream)", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", - sourceMetadata: {} // Needs to be passed in order to get the "modified" state + sourceMetadata: {}, // Needs to be passed in order to get the "modified" state }); t.is(resource.getSourceMetadata().contentModified, false, "sourceMetadata modified flag set correctly"); t.false(resource.isModified(), "Resource is not modified"); const stream = new Stream.Readable(); - stream._read = function() {}; + stream._read = function () {}; stream.push("I am a "); stream.push("readable "); stream.push("stream!"); @@ -429,7 +429,7 @@ test("Resource: setStream (Stream)", async (t) => { test("Resource: setStream (Create stream callback)", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", - sourceMetadata: {} // Needs to be passed in order to get the "modified" state + sourceMetadata: {}, // Needs to be passed in order to get the "modified" state }); t.is(resource.getSourceMetadata().contentModified, false, "sourceMetadata modified flag set correctly"); @@ -437,7 +437,7 @@ test("Resource: setStream (Create stream callback)", async (t) => { resource.setStream(() => { const stream = new Stream.Readable(); - stream._read = function() {}; + stream._read = function () {}; stream.push("I am a "); stream.push("readable "); stream.push("stream!"); @@ -457,7 +457,7 @@ test("Resource: clone resource with buffer", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", - buffer: Buffer.from("Content") + buffer: Buffer.from("Content"), }); const clonedResource = await resource.clone(); @@ -471,10 +471,10 @@ test("Resource: clone resource with stream", async (t) => { t.plan(2); const resource = new Resource({ - path: "/my/path/to/resource" + path: "/my/path/to/resource", }); const stream = new Stream.Readable(); - stream._read = function() {}; + stream._read = function () {}; stream.push("Content"); stream.push(null); @@ -492,8 +492,8 @@ test("Resource: clone resource with sourceMetadata", async (t) => { path: "/my/path/to/resource", sourceMetadata: { adapter: "FileSystem", - fsPath: "/resources/my.js" - } + fsPath: "/resources/my.js", + }, }); const clonedResource = await resource.clone(); @@ -526,12 +526,12 @@ test("Resource: clone resource with sourceMetadata", async (t) => { test("Resource: clone resource with project removes project", async (t) => { const myProject = { - name: "my project" + name: "my project", }; const resource = new Resource({ path: "/my/path/to/resource", - project: myProject + project: myProject, }); const clonedResource = await resource.clone(); @@ -547,8 +547,8 @@ test("Resource: create resource with sourceMetadata.contentModified: true", (t) sourceMetadata: { adapter: "FileSystem", fsPath: "/resources/my.js", - contentModified: true - } + contentModified: true, + }, }); t.true(resource.getSourceMetadata().contentModified, "Modified flag is still true"); @@ -556,7 +556,7 @@ test("Resource: create resource with sourceMetadata.contentModified: true", (t) }); test("getStream with createStream callback content: Subsequent content requests should throw error due " + - "to drained content", async (t) => { +"to drained content", async (t) => { const resource = createBasicResource(); resource.getStream(); t.throws(() => { @@ -567,7 +567,7 @@ test("getStream with createStream callback content: Subsequent content requests }); test("getStream with Buffer content: Subsequent content requests should throw error due to drained " + - "content", async (t) => { +"content", async (t) => { const resource = createBasicResource(); await resource.getBuffer(); resource.getStream(); @@ -579,13 +579,13 @@ test("getStream with Buffer content: Subsequent content requests should throw er }); test("getStream with Stream content: Subsequent content requests should throw error due to drained " + - "content", async (t) => { +"content", async (t) => { const resource = createBasicResource(); const tStream = new Transform({ transform(chunk, encoding, callback) { this.push(chunk.toString()); callback(); - } + }, }); const stream = resource.getStream(); stream.pipe(tStream); @@ -600,13 +600,13 @@ test("getStream with Stream content: Subsequent content requests should throw er }); test("getBuffer from Stream content: Subsequent content requests should not throw error due to drained " + - "content", async (t) => { +"content", async (t) => { const resource = createBasicResource(); const tStream = new Transform({ transform(chunk, encoding, callback) { this.push(chunk.toString()); callback(); - } + }, }); const stream = resource.getStream(); stream.pipe(tStream); @@ -626,7 +626,7 @@ test("Resource: getProject", (t) => { t.plan(1); const resource = new Resource({ path: "/my/path/to/resource", - project: {getName: () => "Mock Project"} + project: {getName: () => "Mock Project"}, }); const project = resource.getProject(); t.is(project.getName(), "Mock Project"); @@ -635,7 +635,7 @@ test("Resource: getProject", (t) => { test("Resource: setProject", (t) => { t.plan(1); const resource = new Resource({ - path: "/my/path/to/resource" + path: "/my/path/to/resource", }); const project = {getName: () => "Mock Project"}; resource.setProject(project); @@ -646,17 +646,17 @@ test("Resource: reassign with setProject", (t) => { t.plan(2); const resource = new Resource({ path: "/my/path/to/resource", - project: {getName: () => "Mock Project"} + project: {getName: () => "Mock Project"}, }); const project = {getName: () => "New Mock Project"}; const error = t.throws(() => resource.setProject(project)); t.is(error.message, "Unable to assign project New Mock Project to resource /my/path/to/resource: " + - "Resource is already associated to project " + project); + "Resource is already associated to project " + project); }); test("Resource: constructor with stream", async (t) => { const stream = new Stream.Readable(); - stream._read = function() {}; + stream._read = function () {}; stream.push("I am a "); stream.push("readable "); stream.push("stream!"); @@ -665,7 +665,7 @@ test("Resource: constructor with stream", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", stream, - sourceMetadata: {} // Needs to be passed in order to get the "modified" state + sourceMetadata: {}, // Needs to be passed in order to get the "modified" state }); t.is(resource.getSourceMetadata().contentModified, false); @@ -686,7 +686,7 @@ test("integration stat - resource size", async (t) => { statInfo, createStream: () => { return createReadStream(fsPath); - } + }, }); t.is(await resource.getSize(), 91); diff --git a/test/lib/ResourceFacade.ts b/test/lib/ResourceFacade.ts index 5dee2fc8..eb2c8798 100644 --- a/test/lib/ResourceFacade.ts +++ b/test/lib/ResourceFacade.ts @@ -3,18 +3,18 @@ import sinon from "sinon"; import Resource from "../../lib/Resource.js"; import ResourceFacade from "../../lib/ResourceFacade.js"; -test.afterEach.always( (t) => { +test.afterEach.always((t) => { sinon.restore(); }); test("Create instance", (t) => { const resource = new Resource({ path: "/my/path/to/resource", - string: "my content" + string: "my content", }); const resourceFacade = new ResourceFacade({ path: "/my/path", - resource + resource, }); t.is(resourceFacade.getPath(), "/my/path", "Returns correct path"); t.is(resourceFacade.getName(), "path", "Returns correct name"); @@ -28,7 +28,7 @@ test("Create instance: Missing parameters", (t) => { }); }, { instanceOf: Error, - message: "Unable to create ResourceFacade: Missing parameter 'resource'" + message: "Unable to create ResourceFacade: Missing parameter 'resource'", }); t.throws(() => { new ResourceFacade({ @@ -36,18 +36,18 @@ test("Create instance: Missing parameters", (t) => { }); }, { instanceOf: Error, - message: "Unable to create ResourceFacade: Missing parameter 'path'" + message: "Unable to create ResourceFacade: Missing parameter 'path'", }); }); test("ResourceFacade #clone", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", - string: "my content" + string: "my content", }); const resourceFacade = new ResourceFacade({ path: "/my/path", - resource + resource, }); const clone = await resourceFacade.clone(); @@ -58,11 +58,11 @@ test("ResourceFacade #clone", async (t) => { test("ResourceFacade #setPath", (t) => { const resource = new Resource({ path: "/my/path/to/resource", - string: "my content" + string: "my content", }); const resourceFacade = new ResourceFacade({ path: "/my/path", - resource + resource, }); const err = t.throws(() => { @@ -74,11 +74,11 @@ test("ResourceFacade #setPath", (t) => { test("ResourceFacade provides same public functions as Resource", (t) => { const resource = new Resource({ path: "/my/path/to/resource", - string: "my content" + string: "my content", }); const resourceFacade = new ResourceFacade({ path: "/my/path", - resource + resource, }); const methods = Object.getOwnPropertyNames(Resource.prototype) diff --git a/test/lib/ResourceTagCollection.ts b/test/lib/ResourceTagCollection.ts index 1329187c..54174469 100644 --- a/test/lib/ResourceTagCollection.ts +++ b/test/lib/ResourceTagCollection.ts @@ -9,10 +9,10 @@ test.afterEach.always((t) => { test("setTag", (t) => { const resource = new Resource({ - path: "/some/path" + path: "/some/path", }); const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:MyTag"] + allowedTags: ["abc:MyTag"], }); const validateResourceSpy = sinon.spy(tagCollection, "_getPath"); @@ -23,8 +23,8 @@ test("setTag", (t) => { t.deepEqual(tagCollection._pathTags, { "/some/path": { - "abc:MyTag": "my value" - } + "abc:MyTag": "my value", + }, }, "Tag correctly stored"); t.is(validateResourceSpy.callCount, 1, "_getPath called once"); @@ -42,26 +42,26 @@ test("setTag", (t) => { test("setTag: Value defaults to true", (t) => { const resource = new Resource({ - path: "/some/path" + path: "/some/path", }); const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:MyTag"] + allowedTags: ["abc:MyTag"], }); tagCollection.setTag(resource, "abc:MyTag"); t.deepEqual(tagCollection._pathTags, { "/some/path": { - "abc:MyTag": true - } + "abc:MyTag": true, + }, }, "Tag correctly stored"); }); test("getTag", (t) => { const resource = new Resource({ - path: "/some/path" + path: "/some/path", }); const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:MyTag"] + allowedTags: ["abc:MyTag"], }); tagCollection.setTag(resource, "abc:MyTag", 123); @@ -83,15 +83,15 @@ test("getTag", (t) => { test("getTag with prefilled tags", (t) => { const resource = new Resource({ - path: "/some/path" + path: "/some/path", }); const tagCollection = new ResourceTagCollection({ allowedTags: ["abc:MyTag"], tags: { "/some/path": { - "abc:MyTag": 123 - } - } + "abc:MyTag": 123, + }, + }, }); const validateResourceSpy = sinon.spy(tagCollection, "_getPath"); @@ -112,10 +112,10 @@ test("getTag with prefilled tags", (t) => { test("clearTag", (t) => { const resource = new Resource({ - path: "/some/path" + path: "/some/path", }); const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:MyTag"] + allowedTags: ["abc:MyTag"], }); tagCollection.setTag(resource, "abc:MyTag", 123); @@ -127,8 +127,8 @@ test("clearTag", (t) => { t.deepEqual(tagCollection._pathTags, { "/some/path": { - "abc:MyTag": undefined - } + "abc:MyTag": undefined, + }, }, "Tag value set to undefined"); t.is(validateResourceSpy.callCount, 1, "_getPath called once"); @@ -142,130 +142,130 @@ test("clearTag", (t) => { test("_validateTag: Not in list of allowed tags", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:MyTag"] + allowedTags: ["abc:MyTag"], }); t.throws(() => { tagCollection._validateTag("abc:MyOtherTag"); }, { instanceOf: Error, message: `Tag "abc:MyOtherTag" not accepted by this collection. ` + - `Accepted tags are: abc:MyTag. Accepted namespaces are: *none*` + `Accepted tags are: abc:MyTag. Accepted namespaces are: *none*`, }); }); test("_validateTag: Empty list of tags and namespaces", (t) => { const tagCollection = new ResourceTagCollection({ allowedTags: [], - allowedNamespaces: [] + allowedNamespaces: [], }); t.throws(() => { tagCollection._validateTag("abc:MyOtherTag"); }, { instanceOf: Error, message: `Tag "abc:MyOtherTag" not accepted by this collection. ` + - `Accepted tags are: *none*. Accepted namespaces are: *none*` + `Accepted tags are: *none*. Accepted namespaces are: *none*`, }); }); test("_validateTag: Missing colon", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["aBcMyTag"] + allowedTags: ["aBcMyTag"], }); t.throws(() => { tagCollection._validateTag("aBcMyTag"); }, { instanceOf: Error, - message: `Invalid Tag "aBcMyTag": Colon required after namespace` + message: `Invalid Tag "aBcMyTag": Colon required after namespace`, }); }); test("_validateTag: Too many colons", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["aBc:My:Tag"] + allowedTags: ["aBc:My:Tag"], }); t.throws(() => { tagCollection._validateTag("aBc:My:Tag"); }, { instanceOf: Error, - message: `Invalid Tag "aBc:My:Tag": Expected exactly one colon but found 2` + message: `Invalid Tag "aBc:My:Tag": Expected exactly one colon but found 2`, }); }); test("_validateTag: Invalid namespace with uppercase letter", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["aBc:MyTag"] + allowedTags: ["aBc:MyTag"], }); t.throws(() => { tagCollection._validateTag("aBc:MyTag"); }, { instanceOf: Error, - message: `Invalid Tag "aBc:MyTag": Namespace part must be alphanumeric, lowercase and start with a letter` + message: `Invalid Tag "aBc:MyTag": Namespace part must be alphanumeric, lowercase and start with a letter`, }); }); test("_validateTag: Invalid namespace starting with number", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["0abc:MyTag"] + allowedTags: ["0abc:MyTag"], }); t.throws(() => { tagCollection._validateTag("0abc:MyTag"); }, { instanceOf: Error, - message: `Invalid Tag "0abc:MyTag": Namespace part must be alphanumeric, lowercase and start with a letter` + message: `Invalid Tag "0abc:MyTag": Namespace part must be alphanumeric, lowercase and start with a letter`, }); }); test("_validateTag: Invalid namespace containing an illegal character", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["a🦦c:MyTag"] + allowedTags: ["a🦦c:MyTag"], }); t.throws(() => { tagCollection._validateTag("a🦦c:MyTag"); }, { instanceOf: Error, - message: `Invalid Tag "a🦦c:MyTag": Namespace part must be alphanumeric, lowercase and start with a letter` + message: `Invalid Tag "a🦦c:MyTag": Namespace part must be alphanumeric, lowercase and start with a letter`, }); }); test("_validateTag: Invalid tag name starting with number", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:0MyTag"] + allowedTags: ["abc:0MyTag"], }); t.throws(() => { tagCollection._validateTag("abc:0MyTag"); }, { instanceOf: Error, - message: `Invalid Tag "abc:0MyTag": Name part must be alphanumeric and start with a capital letter` + message: `Invalid Tag "abc:0MyTag": Name part must be alphanumeric and start with a capital letter`, }); }); test("_validateTag: Invalid tag name starting with lowercase letter", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:myTag"] + allowedTags: ["abc:myTag"], }); t.throws(() => { tagCollection._validateTag("abc:myTag"); }, { instanceOf: Error, - message: `Invalid Tag "abc:myTag": Name part must be alphanumeric and start with a capital letter` + message: `Invalid Tag "abc:myTag": Name part must be alphanumeric and start with a capital letter`, }); }); test("_validateTag: Invalid tag name containing an illegal character", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:My/Tag"] + allowedTags: ["abc:My/Tag"], }); t.throws(() => { tagCollection._validateTag("abc:My/Tag"); }, { instanceOf: Error, - message: `Invalid Tag "abc:My/Tag": Name part must be alphanumeric and start with a capital letter` + message: `Invalid Tag "abc:My/Tag": Name part must be alphanumeric and start with a capital letter`, }); }); test("_validateValue: Valid values", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:MyTag"] + allowedTags: ["abc:MyTag"], }); tagCollection._validateValue("bla"); tagCollection._validateValue(""); @@ -279,50 +279,50 @@ test("_validateValue: Valid values", (t) => { test("_validateValue: Invalid value of type object", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:MyTag"] + allowedTags: ["abc:MyTag"], }); t.throws(() => { tagCollection._validateValue({foo: "bar"}); }, { instanceOf: Error, - message: "Invalid Tag Value: Must be of type string, number or boolean but is object" + message: "Invalid Tag Value: Must be of type string, number or boolean but is object", }); }); test("_validateValue: Invalid value undefined", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:MyTag"] + allowedTags: ["abc:MyTag"], }); t.throws(() => { tagCollection._validateValue(undefined); }, { instanceOf: Error, - message: "Invalid Tag Value: Must be of type string, number or boolean but is undefined" + message: "Invalid Tag Value: Must be of type string, number or boolean but is undefined", }); }); test("_validateValue: Invalid value null", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:MyTag"] + allowedTags: ["abc:MyTag"], }); t.throws(() => { tagCollection._validateValue(null); }, { instanceOf: Error, - message: "Invalid Tag Value: Must be of type string, number or boolean but is object" + message: "Invalid Tag Value: Must be of type string, number or boolean but is object", }); }); test("_getPath: Empty path", (t) => { const tagCollection = new ResourceTagCollection({ - allowedTags: ["abc:MyTag"] + allowedTags: ["abc:MyTag"], }); t.throws(() => { tagCollection._getPath({ - getPath: () => "" + getPath: () => "", }); }, { instanceOf: Error, - message: "Invalid Resource: Resource path must not be empty" + message: "Invalid Resource: Resource path must not be empty", }); }); diff --git a/test/lib/WriterCollection.ts b/test/lib/WriterCollection.ts index 7e389452..736c1c2a 100644 --- a/test/lib/WriterCollection.ts +++ b/test/lib/WriterCollection.ts @@ -11,7 +11,7 @@ test("Constructor: Path mapping regex", (t) => { "/": myWriter, "/my/path/": myWriter, "/my/": myWriter, - } + }, }); t.is(writer._basePathRegex.toString(), "^((?:/)??(?:/my/)??(?:/my/path/)??)+.*?$", "Created correct path mapping regular expression"); @@ -25,7 +25,7 @@ test("Constructor: Path mapping regex has correct escaping", (t) => { "/My\\Weird.Path/": myWriter, "/my/pa$h/": myWriter, "/my/": myWriter, - } + }, }); t.is(writer._basePathRegex.toString(), "^((?:/My\\\\Weird\\.Path/)??(?:/my/)??(?:/my/pa\\$h/)??)+.*?$", "Created correct path mapping regular expression"); @@ -34,7 +34,7 @@ test("Constructor: Path mapping regex has correct escaping", (t) => { test("Constructor: Throws for missing path mapping", (t) => { const err = t.throws(() => { new WriterCollection({ - name: "myCollection" + name: "myCollection", }); }); t.is(err.message, "Cannot create WriterCollection myCollection: Missing parameter 'writerMapping'", @@ -45,7 +45,7 @@ test("Constructor: Throws for empty path mapping", (t) => { const err = t.throws(() => { new WriterCollection({ name: "myCollection", - writerMapping: {} + writerMapping: {}, }); }); t.is(err.message, "Cannot create WriterCollection myCollection: Empty parameter 'writerMapping'", @@ -54,14 +54,14 @@ test("Constructor: Throws for empty path mapping", (t) => { test("Constructor: Throws for empty path", (t) => { const myWriter = { - _write: sinon.stub() + _write: sinon.stub(), }; const err = t.throws(() => { new WriterCollection({ name: "myCollection", writerMapping: { - "": myWriter - } + "": myWriter, + }, }); }); t.is(err.message, "Empty path in path mapping of WriterCollection myCollection", @@ -70,14 +70,14 @@ test("Constructor: Throws for empty path", (t) => { test("Constructor: Throws for missing leading slash", (t) => { const myWriter = { - _write: sinon.stub() + _write: sinon.stub(), }; const err = t.throws(() => { new WriterCollection({ name: "myCollection", writerMapping: { - "my/path/": myWriter - } + "my/path/": myWriter, + }, }); }); t.is(err.message, "Missing leading slash in path mapping 'my/path/' of WriterCollection myCollection", @@ -86,14 +86,14 @@ test("Constructor: Throws for missing leading slash", (t) => { test("Constructor: Throws for missing trailing slash", (t) => { const myWriter = { - _write: sinon.stub() + _write: sinon.stub(), }; const err = t.throws(() => { new WriterCollection({ name: "myCollection", writerMapping: { - "/my/path": myWriter - } + "/my/path": myWriter, + }, }); }); t.is(err.message, "Missing trailing slash in path mapping '/my/path' of WriterCollection myCollection", @@ -102,34 +102,34 @@ test("Constructor: Throws for missing trailing slash", (t) => { test("Write", async (t) => { const myPathWriter = { - _write: sinon.stub() + _write: sinon.stub(), }; const myWriter = { - _write: sinon.stub() + _write: sinon.stub(), }; const generalWriter = { - _write: sinon.stub() + _write: sinon.stub(), }; const writerCollection = new WriterCollection({ name: "myCollection", writerMapping: { "/my/path/": myPathWriter, "/my/": myWriter, - "/": generalWriter - } + "/": generalWriter, + }, }); const myPathResource = new Resource({ path: "/my/path/resource.res", - string: "content" + string: "content", }); const myResource = new Resource({ path: "/my/resource.res", - string: "content" + string: "content", }); const resource = new Resource({ path: "/resource.res", - string: "content" + string: "content", }); await writerCollection.write(myPathResource, "options 1"); @@ -150,21 +150,21 @@ test("Write", async (t) => { test("byGlob", async (t) => { const myPathWriter = { - _byGlob: sinon.stub().resolves([]) + _byGlob: sinon.stub().resolves([]), }; const myWriter = { - _byGlob: sinon.stub().resolves([]) + _byGlob: sinon.stub().resolves([]), }; const generalWriter = { - _byGlob: sinon.stub().resolves([]) + _byGlob: sinon.stub().resolves([]), }; const writerCollection = new WriterCollection({ name: "myCollection", writerMapping: { "/my/path/": myPathWriter, "/my/": myWriter, - "/": generalWriter - } + "/": generalWriter, + }, }); await writerCollection.byGlob("/**"); @@ -180,21 +180,21 @@ test("byGlob", async (t) => { test("byPath", async (t) => { const myPathWriter = { - _byPath: sinon.stub().resolves(null) + _byPath: sinon.stub().resolves(null), }; const myWriter = { - _byPath: sinon.stub().resolves(null) + _byPath: sinon.stub().resolves(null), }; const generalWriter = { - _byPath: sinon.stub().resolves(null) + _byPath: sinon.stub().resolves(null), }; const writerCollection = new WriterCollection({ name: "myCollection", writerMapping: { "/my/path/": myPathWriter, "/my/": myWriter, - "/": generalWriter - } + "/": generalWriter, + }, }); await writerCollection.byPath("/my/resource.res"); diff --git a/test/lib/adapters/AbstractAdapter.ts b/test/lib/adapters/AbstractAdapter.ts index 16a06708..7b8ed299 100644 --- a/test/lib/adapters/AbstractAdapter.ts +++ b/test/lib/adapters/AbstractAdapter.ts @@ -8,38 +8,38 @@ test("Missing paramter: virBasePath", (t) => { t.throws(() => { new MyAbstractAdapter({}); }, { - message: "Unable to create adapter: Missing parameter 'virBasePath'" + message: "Unable to create adapter: Missing parameter 'virBasePath'", }, "Threw with expected error message"); }); test("virBasePath must be absolute", (t) => { t.throws(() => { new MyAbstractAdapter({ - virBasePath: "foo" + virBasePath: "foo", }); }, { - message: "Unable to create adapter: Virtual base path must be absolute but is 'foo'" + message: "Unable to create adapter: Virtual base path must be absolute but is 'foo'", }, "Threw with expected error message"); }); test("virBasePath must end with a slash", (t) => { t.throws(() => { new MyAbstractAdapter({ - virBasePath: "/foo" + virBasePath: "/foo", }); }, { - message: "Unable to create adapter: Virtual base path must end with a slash but is '/foo'" + message: "Unable to create adapter: Virtual base path must end with a slash but is '/foo'", }, "Threw with expected error message"); }); test("_migrateResource", async (t) => { // Any JS object which might be a kind of resource const resource = { - _path: "/test.js" + _path: "/test.js", }; const writer = new MyAbstractAdapter({ - virBasePath: "/" + virBasePath: "/", }); const migratedResource = await writer._migrateResource(resource); @@ -52,16 +52,16 @@ test("_assignProjectToResource: Resource is already assigned to another project path: "/test.js", project: { getName: () => "test.lib", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); const writer = new MyAbstractAdapter({ virBasePath: "/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); const error = t.throws(() => writer._assignProjectToResource(resource)); @@ -74,8 +74,8 @@ test("_isPathHandled", (t) => { virBasePath: "/dest2/writer/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.true(writer._isPathHandled("/dest2/writer/test.js"), "Returned expected result"); @@ -90,8 +90,8 @@ test("_resolveVirtualPathToBase (read mode)", (t) => { virBasePath: "/dest2/writer/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.is(writer._resolveVirtualPathToBase("/dest2/writer/test.js"), "test.js", "Returned expected path"); @@ -106,8 +106,8 @@ test("_resolveVirtualPathToBase (read mode): Path does not starting with path co virBasePath: "/dest2/writer/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.is(writer._resolveVirtualPathToBase("/dest2/tmp/test.js"), null, "Returned null"); @@ -121,13 +121,13 @@ test("_resolveVirtualPathToBase (read mode): Path Must be absolute", (t) => { virBasePath: "/dest2/writer/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.throws(() => writer._resolveVirtualPathToBase("./dest2/write"), { message: - `Failed to resolve virtual path './dest2/write': Path must be absolute` + `Failed to resolve virtual path './dest2/write': Path must be absolute`, }, "Threw with expected error message"); }); @@ -136,8 +136,8 @@ test("_resolveVirtualPathToBase (write mode)", (t) => { virBasePath: "/dest2/writer/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.is(writer._resolveVirtualPathToBase("/dest2/writer/test.js", true), "test.js", "Returned expected path"); @@ -153,32 +153,32 @@ test("_resolveVirtualPathToBase (write mode): Path does not starting with path c virBasePath: "/dest2/writer/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.throws(() => writer._resolveVirtualPathToBase("/dest2/tmp/test.js", true), { message: `Failed to write resource with virtual path '/dest2/tmp/test.js': ` + - `Path must start with the configured virtual base path of the adapter. Base path: '/dest2/writer/'` + `Path must start with the configured virtual base path of the adapter. Base path: '/dest2/writer/'`, }, "Threw with expected error message"); t.throws(() => writer._resolveVirtualPathToBase("/dest2/writer/../reader", true), { message: `Failed to write resource with virtual path '/dest2/writer/../reader': ` + - `Path must start with the configured virtual base path of the adapter. Base path: '/dest2/writer/'` + `Path must start with the configured virtual base path of the adapter. Base path: '/dest2/writer/'`, }, "Threw with expected error message"); t.throws(() => writer._resolveVirtualPathToBase("/dest2/write", true), { message: `Failed to write resource with virtual path '/dest2/write': ` + - `Path must start with the configured virtual base path of the adapter. Base path: '/dest2/writer/'` + `Path must start with the configured virtual base path of the adapter. Base path: '/dest2/writer/'`, }, "Threw with expected error message"); t.throws(() => writer._resolveVirtualPathToBase("/..//write", true), { message: `Failed to write resource with virtual path '/..//write': ` + - `Path must start with the configured virtual base path of the adapter. Base path: '/dest2/writer/'` + `Path must start with the configured virtual base path of the adapter. Base path: '/dest2/writer/'`, }, "Threw with expected error message"); }); @@ -187,13 +187,13 @@ test("_resolveVirtualPathToBase (write mode): Path Must be absolute", (t) => { virBasePath: "/dest2/writer/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.throws(() => writer._resolveVirtualPathToBase("./dest2/write", true), { message: - `Failed to resolve virtual path './dest2/write': Path must be absolute` + `Failed to resolve virtual path './dest2/write': Path must be absolute`, }, "Threw with expected error message"); }); @@ -202,13 +202,13 @@ test("_normalizePattern", async (t) => { virBasePath: "/path/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.deepEqual(await writer._normalizePattern("/*/{src,test}/**"), [ "src/**", - "test/**" + "test/**", ], "Returned expected patterns"); }); @@ -217,8 +217,8 @@ test("_normalizePattern: Match base directory", async (t) => { virBasePath: "/path/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.deepEqual(await writer._normalizePattern("/*"), [""], @@ -230,8 +230,8 @@ test("_normalizePattern: Match sub-directory", async (t) => { virBasePath: "/path/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.deepEqual(await writer._normalizePattern("/path/*"), ["*"], @@ -243,8 +243,8 @@ test("_normalizePattern: Match all", (t) => { virBasePath: "/path/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.deepEqual(writer._normalizePattern("/**/*"), ["**/*"], @@ -256,8 +256,8 @@ test("_normalizePattern: Relative path segment above virtual root directory", (t virBasePath: "/path/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.deepEqual(writer._normalizePattern("/path/../../*"), [], @@ -269,8 +269,8 @@ test("_normalizePattern: Relative path segment resolving to base directory", (t) virBasePath: "/path/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.deepEqual(writer._normalizePattern("/*/../*"), [""], @@ -282,8 +282,8 @@ test("_normalizePattern: Relative path segment", (t) => { virBasePath: "/path/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.deepEqual(writer._normalizePattern("/path/../*"), [""], @@ -295,8 +295,8 @@ test("_normalizePattern: Relative path segment within base directory, matching a virBasePath: "/path/", project: { getName: () => "test.lib1", - getVersion: () => "2.0.0" - } + getVersion: () => "2.0.0", + }, }); t.deepEqual(writer._normalizePattern("/path/path2/../**/*"), ["**/*"], diff --git a/test/lib/adapters/FileSystem.ts b/test/lib/adapters/FileSystem.ts index 9e41965b..cfcc9d1a 100644 --- a/test/lib/adapters/FileSystem.ts +++ b/test/lib/adapters/FileSystem.ts @@ -5,9 +5,9 @@ import FileSystem from "../../../lib/adapters/FileSystem.js"; test.serial("Missing parameter: fsBasePath", (t) => { t.throws(() => { new FileSystem({ - virBasePath: "/" + virBasePath: "/", }); }, { - message: "Unable to create adapter: Missing parameter 'fsBasePath'" + message: "Unable to create adapter: Missing parameter 'fsBasePath'", }, "Threw with expected error message"); }); diff --git a/test/lib/adapters/FileSystem_read.ts b/test/lib/adapters/FileSystem_read.ts index f5bee36f..65bb99a0 100644 --- a/test/lib/adapters/FileSystem_read.ts +++ b/test/lib/adapters/FileSystem_read.ts @@ -7,7 +7,7 @@ import {createAdapter} from "../../../lib/resourceFactory.js"; test("glob resources from application.a w/ virtual base path prefix", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }); const resources = await readerWriter.byGlob("/app/**/*.html"); @@ -17,7 +17,7 @@ test("glob resources from application.a w/ virtual base path prefix", async (t) test("glob resources from application.a w/o virtual base path prefix", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }); const resources = await readerWriter.byGlob("/**/*.html"); @@ -27,7 +27,7 @@ test("glob resources from application.a w/o virtual base path prefix", async (t) test("glob virtual directory w/o virtual base path prefix", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }); const resources = await readerWriter.byGlob("/*", {nodir: false}); @@ -37,12 +37,12 @@ test("glob virtual directory w/o virtual base path prefix", async (t) => { test("glob virtual directory w/o virtual base path prefix and multiple patterns", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }); const resources = await readerWriter.byGlob([ "/*", - "/*" + "/*", ], {nodir: false}); t.is(resources.length, 1, "Found exactly one resource"); }); @@ -50,7 +50,7 @@ test("glob virtual directory w/o virtual base path prefix and multiple patterns" test("glob virtual directory w/ virtual base path prefix", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/one/two/" + virBasePath: "/app/one/two/", }); const resources = await readerWriter.byGlob("/app/*", {nodir: false}); @@ -60,7 +60,7 @@ test("glob virtual directory w/ virtual base path prefix", async (t) => { test("glob virtual directory w/o virtual base path prefix and nodir: true", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }); const resources = await readerWriter.byGlob("/*", {nodir: true}); @@ -70,12 +70,12 @@ test("glob virtual directory w/o virtual base path prefix and nodir: true", asyn test("glob virtual directory w/o virtual base path prefix and nodir: true and multiple patterns", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }); const resources = await readerWriter.byGlob([ "/*", - "/*" + "/*", ], {nodir: true}); t.is(resources.length, 0, "Found no resources"); }); @@ -83,7 +83,7 @@ test("glob virtual directory w/o virtual base path prefix and nodir: true and mu test("glob virtual directory w/ virtual base path prefix and nodir: true", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/one/two/" + virBasePath: "/app/one/two/", }); const resources = await readerWriter.byGlob("/app/*", {nodir: true}); @@ -93,10 +93,10 @@ test("glob virtual directory w/ virtual base path prefix and nodir: true", async test("glob resources from application.a with directory exclude", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }); - await readerWriter.byGlob("/!(pony,unicorn)/**").then(function(resources) { + await readerWriter.byGlob("/!(pony,unicorn)/**").then(function (resources) { t.is(resources.length, 2, "Found exactly two resource"); }); }); @@ -104,7 +104,7 @@ test("glob resources from application.a with directory exclude", async (t) => { test("glob all above virtual base path (path traversal)", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }); const res = await readerWriter.byGlob([ @@ -116,7 +116,7 @@ test("glob all above virtual base path (path traversal)", async (t) => { test("glob virtual directory above virtual base path (path traversal)", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }); const res = await readerWriter.byGlob([ @@ -134,7 +134,7 @@ test("glob not existing directory with existing file path (nodir: true)", async // globby will throw if it is attempted to glob the content of a directory // which is actually a file await t.throwsAsync(srcReader.byGlob("/test/library/l/Test.html/*", {nodir: true}), { - message: /ENOTDIR/ + message: /ENOTDIR/, }, "Threw with expected error message"); }); @@ -147,14 +147,14 @@ test("glob not existing directory with existing file path (nodir: false)", async // globby will throw if it is attempted to glob the content of a directory // which is actually a file await t.throwsAsync(srcReader.byGlob("/test/library/l/Test.html/*", {nodir: false}), { - message: /ENOTDIR/ + message: /ENOTDIR/, }, "Threw with expected error message"); }); test("byPath", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/resources/app/" + virBasePath: "/resources/app/", }); const resource = await readerWriter.byPath("/resources/app/index.html", {nodir: true}); @@ -164,7 +164,7 @@ test("byPath", async (t) => { test("byPath virtual directory above base path (path traversal)", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/resources/app/" + virBasePath: "/resources/app/", }); const resource = await readerWriter.byPath("/resources/app/../package.json", {nodir: true}); @@ -174,7 +174,7 @@ test("byPath virtual directory above base path (path traversal)", async (t) => { test("byPath: Root dir w/ trailing slash", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/resources/app/" + virBasePath: "/resources/app/", }); const resource = await readerWriter.byPath("/resources/app/", {nodir: false}); @@ -184,7 +184,7 @@ test("byPath: Root dir w/ trailing slash", async (t) => { test("byPath: Root dir w/o trailing slash", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/resources/app/" + virBasePath: "/resources/app/", }); const resource = await readerWriter.byPath("/resources/app", {nodir: false}); @@ -194,7 +194,7 @@ test("byPath: Root dir w/o trailing slash", async (t) => { test("byPath: Virtual directory w/ trailing slash", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/resources/app/" + virBasePath: "/resources/app/", }); const resource = await readerWriter.byPath("/resources/", {nodir: false}); @@ -204,7 +204,7 @@ test("byPath: Virtual directory w/ trailing slash", async (t) => { test("byPath: Virtual directory w/o trailing slash", async (t) => { const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/resources/app/" + virBasePath: "/resources/app/", }); const resource = await readerWriter.byPath("/resources", {nodir: false}); @@ -216,7 +216,7 @@ test("byPath: Incorrect virtual directory w/o trailing slash", async (t) => { // tested elsewhere const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/resources/app/" + virBasePath: "/resources/app/", }); // TODO: This should actually not match @@ -240,13 +240,13 @@ test("static excludes: glob library src and test", async (t) => { const srcReader = createAdapter({ fsBasePath: "./test/fixtures/library.l/src", virBasePath: "/resources/", - excludes + excludes, }); const testReader = createAdapter({ fsBasePath: "./test/fixtures/library.l/test", virBasePath: "/test-resources/", - excludes + excludes, }); const srcResources = await srcReader.byGlob("/**/*", {nodir: true}); @@ -254,7 +254,7 @@ test("static excludes: glob library src and test", async (t) => { t.is(srcResources.length, 1, "Found one src resource"); t.deepEqual(srcResources.map(getPathFromResource), [ - "/resources/library/l/.library" + "/resources/library/l/.library", ], "Found expected src resources"); t.is(testResources.length, 0, "Found no test resources"); @@ -271,13 +271,13 @@ test("static excludes: glob library src and test with double negation", async (t const srcReader = createAdapter({ fsBasePath: "./test/fixtures/library.l/src", virBasePath: "/resources/", - excludes + excludes, }); const testReader = createAdapter({ fsBasePath: "./test/fixtures/library.l/test", virBasePath: "/test-resources/", - excludes + excludes, }); const srcResources = await srcReader.byGlob("/**/*", {nodir: true}); @@ -285,12 +285,12 @@ test("static excludes: glob library src and test with double negation", async (t t.is(srcResources.length, 1, "Found one src resource"); t.deepEqual(srcResources.map(getPathFromResource), [ - "/resources/library/l/.library" + "/resources/library/l/.library", ], "Found expected src resources"); t.is(testResources.length, 1, "Found one test resource"); t.deepEqual(testResources.map(getPathFromResource), [ - "/test-resources/library/l/Test2.html" + "/test-resources/library/l/Test2.html", ], "Found expected test resources"); }); @@ -305,14 +305,14 @@ test("static excludes: glob library test with double negation", async (t) => { const testReader = createAdapter({ fsBasePath: "./test/fixtures/library.l/test", virBasePath: "/test-resources/", - excludes + excludes, }); const testResources = await testReader.byGlob("/**/*", {nodir: true}); t.is(testResources.length, 1, "Found one test resource"); t.deepEqual(testResources.map(getPathFromResource), [ - "/test-resources/library/l/Test2.html" + "/test-resources/library/l/Test2.html", ], "Found expected test resources"); }); @@ -321,8 +321,8 @@ test("static excludes: glob with virtual root exclude", async (t) => { fsBasePath: "./test/fixtures/library.l/src", virBasePath: "/resources/", excludes: [ - "/**" - ] + "/**", + ], }); const resources = await srcReader.byGlob("/**/*", {nodir: true}); @@ -335,8 +335,8 @@ test("static excludes: glob with negated directory exclude, excluding resources" fsBasePath: "./test/fixtures/library.l/src", virBasePath: "/resources/", excludes: [ - "/!({pony,unicorn})/**" - ] + "/!({pony,unicorn})/**", + ], }); const resources = await srcReader.byGlob("/**/*", {nodir: true}); @@ -349,8 +349,8 @@ test("static excludes: glob with negated directory exclude, not excluding resour fsBasePath: "./test/fixtures/library.l/src", virBasePath: "/resources/", excludes: [ - "/!(resources)/**" - ] + "/!(resources)/**", + ], }); const resources = await srcReader.byGlob("/**/*", {nodir: true}); @@ -362,7 +362,7 @@ test("static excludes: byPath exclude everything in sub-directory", async (t) => const readerWriter = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", virBasePath: "/resources/app/", - excludes: ["/resources/app/**"] + excludes: ["/resources/app/**"], }); const resource = await readerWriter.byPath("/resources/app/index.html", {nodir: true}); @@ -375,8 +375,8 @@ test("static excludes: byPath exclude with negation", async (t) => { virBasePath: "/resources/app/", excludes: [ "/resources/app/**", - "!/resources/app/index.html" - ] + "!/resources/app/index.html", + ], }); const resource = await readerWriter.byPath("/resources/app/index.html", {nodir: true}); @@ -389,8 +389,8 @@ test("static excludes: byPath exclude with unused negation", async (t) => { virBasePath: "/resources/app/", excludes: [ "!/resources/app/index.html", - "/resources/app/**" - ] + "/resources/app/**", + ], }); const resource = await readerWriter.byPath("/resources/app/index.html", {nodir: true}); @@ -402,8 +402,8 @@ test("static excludes: byPath exclude with negated directory pattern, excluding fsBasePath: "./test/fixtures/application.a/webapp", virBasePath: "/resources/app/", excludes: [ - "/!({pony,unicorn})/**" - ] + "/!({pony,unicorn})/**", + ], }); const resource = await readerWriter.byPath("/resources/app/index.html", {nodir: true}); @@ -415,8 +415,8 @@ test("static excludes: byPath exclude with negated directory pattern, not exclud fsBasePath: "./test/fixtures/application.a/webapp", virBasePath: "/resources/app/", excludes: [ - "/!(resources)/**" - ] + "/!(resources)/**", + ], }); const resource = await readerWriter.byPath("/resources/app/index.html", {nodir: true}); @@ -430,14 +430,14 @@ test("byPath: exclude with unused negation", async (t) => { excludes: [ "!/resources/app/i18n/**", "/resources/app/**", - "!/resources/app/manifest.json" - ] + "!/resources/app/manifest.json", + ], }); const [manifest, i18n, i18ni18n] = await Promise.all([ readerWriter.byPath("/resources/app/manifest.json", {nodir: true}), readerWriter.byPath("/resources/app/i18n.properties", {nodir: true}), - readerWriter.byPath("/resources/app/i18n/i18n.properties", {nodir: true}) + readerWriter.byPath("/resources/app/i18n/i18n.properties", {nodir: true}), ]); t.truthy(manifest, "Found manifest.json resource"); t.is(i18n, null, "i18n resource is excluded"); @@ -455,13 +455,13 @@ test("static excludes: glob library src and test with double negation (nodir: fa const srcReader = createAdapter({ fsBasePath: "./test/fixtures/library.l/src", virBasePath: "/resources/", - excludes + excludes, }); const testReader = createAdapter({ fsBasePath: "./test/fixtures/library.l/test", virBasePath: "/test-resources/", - excludes + excludes, }); const srcResources = await srcReader.byGlob("/**/*", {nodir: false}); @@ -471,7 +471,7 @@ test("static excludes: glob library src and test with double negation (nodir: fa t.is(testResources.length, 1, "Found one test resource"); t.deepEqual(testResources.map(getPathFromResource), [ - "/test-resources/library/l/Test2.html" + "/test-resources/library/l/Test2.html", ], "Found expected test resources"); }); @@ -480,8 +480,8 @@ test("static excludes: glob with virtual root exclude (nodir: false)", async (t) fsBasePath: "./test/fixtures/library.l/src", virBasePath: "/resources/", excludes: [ - "/**" - ] + "/**", + ], }); const resources = await srcReader.byGlob("/**/*", {nodir: false}); @@ -493,8 +493,8 @@ test("static excludes: glob with negated directory exclude, excluding resources fsBasePath: "./test/fixtures/library.l/src", virBasePath: "/resources/", excludes: [ - "/!({pony,unicorn})/**" - ] + "/!({pony,unicorn})/**", + ], }); const resources = await srcReader.byGlob("/**/*", {nodir: false}); @@ -507,8 +507,8 @@ test("static excludes: glob with negated directory exclude, not excluding resour fsBasePath: "./test/fixtures/library.l/src", virBasePath: "/resources/", excludes: [ - "/!(resources)/**" - ] + "/!(resources)/**", + ], }); const resources = await srcReader.byGlob("/**/*", {nodir: false}); @@ -521,8 +521,8 @@ test("static excludes: glob with exclude (nodir: false)", async (t) => { fsBasePath: "./test/fixtures/library.l/", virBasePath: "/", excludes: [ - "/test/**" - ] + "/test/**", + ], }); const resources = await srcReader.byGlob("/test/library/l/Test.html", {nodir: false}); @@ -534,7 +534,7 @@ test("glob with useGitignore: true", async (t) => { const srcReader = createAdapter({ fsBasePath: "./test/fixtures/library.l/", virBasePath: "/", - useGitignore: true + useGitignore: true, }); const resources = await srcReader.byGlob("/**/*"); @@ -554,16 +554,16 @@ test("byPath with useGitignore: true", async (t) => { const isGitIgnoredSpy = sinon.stub().callsFake(isGitIgnored); const FileSystem = await esmock("../../../lib/adapters/FileSystem.js", { - "globby": { - isGitIgnored: isGitIgnoredSpy - } + globby: { + isGitIgnored: isGitIgnoredSpy, + }, }); const fsBasePath = "./test/fixtures/library.l/"; const srcReader = new FileSystem({ fsBasePath, virBasePath: "/", - useGitignore: true + useGitignore: true, }); const testResource = await srcReader.byPath("/test/library/l/Test.html"); diff --git a/test/lib/adapters/FileSystem_write.ts b/test/lib/adapters/FileSystem_write.ts index 8386c2a5..99927d47 100644 --- a/test/lib/adapters/FileSystem_write.ts +++ b/test/lib/adapters/FileSystem_write.ts @@ -33,12 +33,12 @@ test.beforeEach(async (t) => { t.context.readerWriters = { source: createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }), dest: createAdapter({ fsBasePath: "./test/tmp/adapters/FileSystemWrite/" + tmpDirName, - virBasePath: "/app/" - }) + virBasePath: "/app/", + }), }; }); @@ -127,7 +127,7 @@ test("Write with readOnly and drain options set should fail", async (t) => { // Write resource content to another readerWriter await t.throwsAsync(readerWriters.dest.write(resource, {readOnly: true, drain: true}), { message: "Error while writing resource /app/index.html: " + - "Do not use options 'drain' and 'readOnly' at the same time." + "Do not use options 'drain' and 'readOnly' at the same time.", }); }); diff --git a/test/lib/adapters/FileSystem_write_large_file.ts b/test/lib/adapters/FileSystem_write_large_file.ts index bb8fbfb6..f812470b 100644 --- a/test/lib/adapters/FileSystem_write_large_file.ts +++ b/test/lib/adapters/FileSystem_write_large_file.ts @@ -16,14 +16,14 @@ test.serial("Stream a large file from source to target", async (t) => { const fileSystem = new FileSystem({ fsBasePath, - virBasePath: "/" + virBasePath: "/", }); const largeBuffer = Buffer.alloc(1048576); // 1MB await fileSystem.write(new Resource({ path: "/large-file.txt", - buffer: largeBuffer + buffer: largeBuffer, })); t.deepEqual(await readFile(path.join(fsBasePath, "large-file.txt")), largeBuffer, diff --git a/test/lib/adapters/Memory_read.ts b/test/lib/adapters/Memory_read.ts index 70a034b2..eda4e482 100644 --- a/test/lib/adapters/Memory_read.ts +++ b/test/lib/adapters/Memory_read.ts @@ -8,7 +8,7 @@ async function fillFromFs(readerWriter, {fsBasePath = "./test/fixtures/glob", vi }); const fsResources = await fsReader.byGlob("/**/*"); - return Promise.all(fsResources.map(function(resource) { + return Promise.all(fsResources.map(function (resource) { return readerWriter.write(resource); })); } @@ -31,12 +31,12 @@ function matchGlobResult(t, resources, expectedResources) { test("glob resources from application.a w/ virtual base path prefix", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); const resource = createResource({ path: "/app/index.html", - string: "test" + string: "test", }); await readerWriter.write(resource); @@ -46,12 +46,12 @@ test("glob resources from application.a w/ virtual base path prefix", async (t) test("glob resources from application.a w/o virtual base path prefix", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); const resource = createResource({ path: "/app/index.html", - string: "test" + string: "test", }); await readerWriter.write(resource); @@ -62,7 +62,7 @@ test("glob resources from application.a w/o virtual base path prefix", async (t) test("glob virtual directory w/o virtual base path prefix", async (t) => { // TODO: Add similar test (globbing on empty directory) for FS RL const readerWriter = createAdapter({ - virBasePath: "/app/one/two/" + virBasePath: "/app/one/two/", }); const resources = await readerWriter.byGlob("/*", {nodir: false}); @@ -72,12 +72,12 @@ test("glob virtual directory w/o virtual base path prefix", async (t) => { test("glob virtual directory w/o virtual base path prefix and multiple patterns", async (t) => { // TODO: Add similar test (globbing on empty directory) for FS RL const readerWriter = createAdapter({ - virBasePath: "/app/one/two/" + virBasePath: "/app/one/two/", }); const resources = await readerWriter.byGlob([ "/*", - "/*" + "/*", ], {nodir: false}); t.is(resources.length, 1, "Found exactly one resource"); }); @@ -85,7 +85,7 @@ test("glob virtual directory w/o virtual base path prefix and multiple patterns" test("glob virtual directory w/ virtual base path prefix", async (t) => { // TODO: Add similar test (globbing on empty directory) for FS RL const readerWriter = createAdapter({ - virBasePath: "/app/one/two/" + virBasePath: "/app/one/two/", }); const resources = await readerWriter.byGlob("/app/*", {nodir: false}); @@ -94,7 +94,7 @@ test("glob virtual directory w/ virtual base path prefix", async (t) => { test("glob virtual directory w/o virtual base path prefix and nodir: true", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/one/two/" + virBasePath: "/app/one/two/", }); const resources = await readerWriter.byGlob("/*", {nodir: true}); @@ -103,7 +103,7 @@ test("glob virtual directory w/o virtual base path prefix and nodir: true", asyn test("glob virtual directory w/ virtual base path prefix and nodir: true", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/one/two/" + virBasePath: "/app/one/two/", }); const resources = await readerWriter.byGlob("/app/*", {nodir: true}); @@ -112,12 +112,12 @@ test("glob virtual directory w/ virtual base path prefix and nodir: true", async test("glob virtual directory w/ virtual base path prefix and nodir: true and multiple patterns", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/one/two/" + virBasePath: "/app/one/two/", }); const resources = await readerWriter.byGlob([ "/*", - "/*" + "/*", ], {nodir: true}); t.is(resources.length, 0, "Found no resources"); }); @@ -125,7 +125,7 @@ test("glob virtual directory w/ virtual base path prefix and nodir: true and mul /* Load more data from FS into memory */ test("glob all", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter); const resources = await readerWriter.byGlob("/**/*.*"); @@ -135,7 +135,7 @@ test("glob all", async (t) => { test("glob all from root", async (t) => { t.plan(2); const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter); const resources = await readerWriter.byGlob("/*/*.*"); @@ -144,7 +144,7 @@ test("glob all from root", async (t) => { test("glob all with virtual path included", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter); @@ -155,7 +155,7 @@ test("glob all with virtual path included", async (t) => { test("glob a specific filetype (yaml)", async (t) => { t.plan(2); const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter); @@ -168,7 +168,7 @@ test("glob a specific filetype (yaml)", async (t) => { test("glob two specific filetype (yaml and js)", async (t) => { t.plan(4); const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter); @@ -176,7 +176,7 @@ test("glob two specific filetype (yaml and js)", async (t) => { const expectedFiles = [ "/app/application.b/ui5.yaml", "/app/application.a/ui5.yaml", - "/app/application.a/webapp/test.js" + "/app/application.a/webapp/test.js", ]; matchGlobResult(t, resources, expectedFiles); }); @@ -184,17 +184,17 @@ test("glob two specific filetype (yaml and js)", async (t) => { test("glob a specific filetype (json) with exclude pattern", async (t) => { t.plan(3); const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter); const resources = await readerWriter.byGlob([ "/**/*.json", - "!/**/*package.json" + "!/**/*package.json", ]); const expectedFiles = [ "/app/application.b/webapp/manifest.json", - "/app/application.b/webapp/embedded/manifest.json" + "/app/application.b/webapp/embedded/manifest.json", ]; matchGlobResult(t, resources, expectedFiles); }); @@ -202,14 +202,14 @@ test("glob a specific filetype (json) with exclude pattern", async (t) => { test("glob a specific filetype (json) with multiple exclude pattern", async (t) => { t.plan(2); const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter); const resources = await readerWriter.byGlob([ "/**/*.json", "!/**/*package.json", - "!/**/embedded/manifest.json" + "!/**/embedded/manifest.json", ]); matchGlobResult(t, resources, ["/app/application.b/webapp/manifest.json"]); }); @@ -217,7 +217,7 @@ test("glob a specific filetype (json) with multiple exclude pattern", async (t) test("glob (normalized) root directory (=> fs root)", async (t) => { t.plan(2); const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter); @@ -233,7 +233,7 @@ test("glob (normalized) root directory (=> fs root)", async (t) => { test("glob root directory", async (t) => { t.plan(2); const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter); @@ -244,7 +244,7 @@ test("glob root directory", async (t) => { test("glob subdirectory", async (t) => { t.plan(3); const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter); @@ -259,7 +259,7 @@ test("glob subdirectory", async (t) => { test("glob all resources above virtual base path (path traversal)", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter, { fsBasePath: "./test/fixtures/application.a/webapp", @@ -274,7 +274,7 @@ test("glob all resources above virtual base path (path traversal)", async (t) => test("glob virtual directory above virtual base path (path traversal)", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); await fillFromFs(readerWriter, { fsBasePath: "./test/fixtures/application.a/webapp", @@ -289,7 +289,7 @@ test("glob virtual directory above virtual base path (path traversal)", async (t test("byPath", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/resources/app/" + virBasePath: "/resources/app/", }); await fillFromFs(readerWriter, { fsBasePath: "./test/fixtures/application.a/webapp", @@ -302,7 +302,7 @@ test("byPath", async (t) => { test("byPath virtual directory above base path (path traversal)", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/resources/app/" + virBasePath: "/resources/app/", }); await fillFromFs(readerWriter, { fsBasePath: "./test/fixtures/application.a/webapp", @@ -313,7 +313,6 @@ test("byPath virtual directory above base path (path traversal)", async (t) => { t.is(resource, null, "Found no resource"); }); - function getPathFromResource(resource) { return resource.getPath(); } @@ -329,7 +328,7 @@ test("static excludes: glob library src and test", async (t) => { ]; const srcReader = createAdapter({ virBasePath: "/resources/", - excludes + excludes, }); await fillFromFs(srcReader, { fsBasePath: "./test/fixtures/library.l/src", @@ -338,7 +337,7 @@ test("static excludes: glob library src and test", async (t) => { const testReader = createAdapter({ virBasePath: "/test-resources/", - excludes + excludes, }); await fillFromFs(testReader, { fsBasePath: "./test/fixtures/library.l/test", @@ -350,7 +349,7 @@ test("static excludes: glob library src and test", async (t) => { t.is(srcResources.length, 1, "Found one src resource"); t.deepEqual(srcResources.map(getPathFromResource), [ - "/resources/library/l/.library" + "/resources/library/l/.library", ], "Found expected src resources"); t.is(testResources.length, 0, "Found no test resources"); @@ -366,7 +365,7 @@ test("static excludes: glob library src and test with double negation", async (t ]; const srcReader = createAdapter({ virBasePath: "/resources/", - excludes + excludes, }); await fillFromFs(srcReader, { fsBasePath: "./test/fixtures/library.l/src", @@ -375,11 +374,11 @@ test("static excludes: glob library src and test with double negation", async (t const testReader = createAdapter({ virBasePath: "/test-resources/", - excludes + excludes, }); await fillFromFs(testReader, { fsBasePath: "./test/fixtures/library.l/test", - virBasePath: "/test-resources/" + virBasePath: "/test-resources/", }); const srcResources = await srcReader.byGlob("/**/*", {nodir: true}); @@ -387,12 +386,12 @@ test("static excludes: glob library src and test with double negation", async (t t.is(srcResources.length, 1, "Found one src resource"); t.deepEqual(srcResources.map(getPathFromResource), [ - "/resources/library/l/.library" + "/resources/library/l/.library", ], "Found expected src resources"); t.is(testResources.length, 1, "Found one test resource"); t.deepEqual(testResources.map(getPathFromResource), [ - "/test-resources/library/l/Test2.html" + "/test-resources/library/l/Test2.html", ], "Found expected test resources"); }); @@ -406,18 +405,18 @@ test("static excludes: glob library test with double negation", async (t) => { const testReader = createAdapter({ virBasePath: "/test-resources/", - excludes + excludes, }); await fillFromFs(testReader, { fsBasePath: "./test/fixtures/library.l/test", - virBasePath: "/test-resources/" + virBasePath: "/test-resources/", }); const testResources = await testReader.byGlob("/**/*", {nodir: true}); t.is(testResources.length, 1, "Found one test resource"); t.deepEqual(testResources.map(getPathFromResource), [ - "/test-resources/library/l/Test2.html" + "/test-resources/library/l/Test2.html", ], "Found expected test resources"); }); @@ -425,8 +424,8 @@ test("static excludes: glob with virtual root exclude", async (t) => { const srcReader = createAdapter({ virBasePath: "/resources/", excludes: [ - "/**" - ] + "/**", + ], }); await fillFromFs(srcReader, { fsBasePath: "./test/fixtures/library.l/src", @@ -442,8 +441,8 @@ test("static excludes: glob with negated directory exclude, excluding resources" const srcReader = createAdapter({ virBasePath: "/resources/", excludes: [ - "/!({pony,unicorn})/**" - ] + "/!({pony,unicorn})/**", + ], }); await fillFromFs(srcReader, { fsBasePath: "./test/fixtures/library.l/src", @@ -459,8 +458,8 @@ test("static excludes: glob with negated directory exclude, not excluding resour const srcReader = createAdapter({ virBasePath: "/resources/", excludes: [ - "/!(resources)/**" - ] + "/!(resources)/**", + ], }); await fillFromFs(srcReader, { fsBasePath: "./test/fixtures/library.l/src", @@ -475,7 +474,7 @@ test("static excludes: glob with negated directory exclude, not excluding resour test("static excludes: byPath exclude everything in sub-directory", async (t) => { const readerWriter = createAdapter({ virBasePath: "/resources/app/", - excludes: ["/resources/app/**"] + excludes: ["/resources/app/**"], }); await fillFromFs(readerWriter, { fsBasePath: "./test/fixtures/application.a/webapp", @@ -491,8 +490,8 @@ test("static excludes: byPath exclude with negation", async (t) => { virBasePath: "/resources/app/", excludes: [ "/resources/app/**", - "!/resources/app/index.html" - ] + "!/resources/app/index.html", + ], }); await fillFromFs(readerWriter, { fsBasePath: "./test/fixtures/application.a/webapp", @@ -508,8 +507,8 @@ test("static excludes: byPath exclude with unused negation", async (t) => { virBasePath: "/resources/app/", excludes: [ "!/resources/app/index.html", - "/resources/app/**" - ] + "/resources/app/**", + ], }); await fillFromFs(readerWriter, { fsBasePath: "./test/fixtures/application.a/webapp", @@ -524,8 +523,8 @@ test("static excludes: byPath exclude with negated directory pattern, excluding const readerWriter = createAdapter({ virBasePath: "/resources/app/", excludes: [ - "/!({pony,unicorn})/**" - ] + "/!({pony,unicorn})/**", + ], }); await fillFromFs(readerWriter, { fsBasePath: "./test/fixtures/application.a/webapp", @@ -540,8 +539,8 @@ test("static excludes: byPath exclude with negated directory pattern, not exclud const readerWriter = createAdapter({ virBasePath: "/resources/app/", excludes: [ - "/!(resources)/**" - ] + "/!(resources)/**", + ], }); await fillFromFs(readerWriter, { fsBasePath: "./test/fixtures/application.a/webapp", @@ -558,8 +557,8 @@ test("byPath: exclude with unused negation", async (t) => { excludes: [ "!/resources/app/i18n/**", "/resources/app/**", - "!/resources/app/manifest.json" - ] + "!/resources/app/manifest.json", + ], }); await fillFromFs(readerWriter, { fsBasePath: "./test/fixtures/application.b/webapp", @@ -569,7 +568,7 @@ test("byPath: exclude with unused negation", async (t) => { const [manifest, i18n, i18ni18n] = await Promise.all([ readerWriter.byPath("/resources/app/manifest.json", {nodir: true}), readerWriter.byPath("/resources/app/i18n.properties", {nodir: true}), - readerWriter.byPath("/resources/app/i18n/i18n.properties", {nodir: true}) + readerWriter.byPath("/resources/app/i18n/i18n.properties", {nodir: true}), ]); t.truthy(manifest, "Found manifest.json resource"); t.is(i18n, null, "i18n resource is excluded"); @@ -586,7 +585,7 @@ test("static excludes: glob library src and test with double negation (nodir: fa ]; const srcReader = createAdapter({ virBasePath: "/resources/", - excludes + excludes, }); await fillFromFs(srcReader, { fsBasePath: "./test/fixtures/library.l/src", @@ -595,7 +594,7 @@ test("static excludes: glob library src and test with double negation (nodir: fa const testReader = createAdapter({ virBasePath: "/test-resources/", - excludes + excludes, }); await fillFromFs(testReader, { fsBasePath: "./test/fixtures/library.l/test", @@ -609,7 +608,7 @@ test("static excludes: glob library src and test with double negation (nodir: fa t.is(testResources.length, 1, "Found one test resource"); t.deepEqual(testResources.map(getPathFromResource), [ - "/test-resources/library/l/Test2.html" + "/test-resources/library/l/Test2.html", ], "Found expected test resources"); }); @@ -617,8 +616,8 @@ test("static excludes: glob with virtual root exclude (nodir: false)", async (t) const srcReader = createAdapter({ virBasePath: "/resources/", excludes: [ - "/**" - ] + "/**", + ], }); await fillFromFs(srcReader, { fsBasePath: "./test/fixtures/library.l/src", @@ -633,8 +632,8 @@ test("static excludes: glob with negated directory exclude, excluding resources const srcReader = createAdapter({ virBasePath: "/resources/", excludes: [ - "/!({pony,unicorn})/**" - ] + "/!({pony,unicorn})/**", + ], }); await fillFromFs(srcReader, { fsBasePath: "./test/fixtures/library.l/src", @@ -650,8 +649,8 @@ test("static excludes: glob with negated directory exclude, not excluding resour const srcReader = createAdapter({ virBasePath: "/resources/", excludes: [ - "/!(resources)/**" - ] + "/!(resources)/**", + ], }); await fillFromFs(srcReader, { fsBasePath: "./test/fixtures/library.l/src", @@ -666,7 +665,7 @@ test("static excludes: glob with negated directory exclude, not excluding resour test("byPath returns new resource", async (t) => { const originalResource = createResource({ path: "/app/index.html", - string: "test" + string: "test", }); const memoryAdapter = createAdapter({virBasePath: "/"}); @@ -694,7 +693,7 @@ test("byPath returns new resource", async (t) => { test("byGlob returns new resources", async (t) => { const originalResource = createResource({ path: "/app/index.html", - string: "test" + string: "test", }); const memoryAdapter = createAdapter({virBasePath: "/"}); diff --git a/test/lib/adapters/Memory_write.ts b/test/lib/adapters/Memory_write.ts index d1cbad8a..b9863c8b 100644 --- a/test/lib/adapters/Memory_write.ts +++ b/test/lib/adapters/Memory_write.ts @@ -4,11 +4,11 @@ import sinon from "sinon"; test("glob resources from application.a w/ virtual base path prefix", async (t) => { const dest = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); const res = createResource({ - path: "/app/index.html" + path: "/app/index.html", }); await dest.write(res); const resources = await dest.byGlob("/app/*.html"); @@ -18,11 +18,11 @@ test("glob resources from application.a w/ virtual base path prefix", async (t) test("glob resources from application.a w/o virtual base path prefix", async (t) => { const dest = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); const res = createResource({ - path: "/app/index.html" + path: "/app/index.html", }); await dest.write(res); const resources = await dest.byGlob("/**/*.html"); @@ -31,16 +31,16 @@ test("glob resources from application.a w/o virtual base path prefix", async (t) test("Write resource w/ virtual base path", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/" + virBasePath: "/app/", }); const res = createResource({ - path: "/app/test.html" + path: "/app/test.html", }); await readerWriter.write(res); t.deepEqual(readerWriter._virFiles, { - "test.html": res + "test.html": res, }, "Adapter added resource with correct path"); t.deepEqual(Object.keys(readerWriter._virDirs), [], "Adapter added correct virtual directories"); @@ -49,22 +49,22 @@ test("Write resource w/ virtual base path", async (t) => { test("Write resource w/o virtual base path", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/" + virBasePath: "/", }); const res = createResource({ - path: "/one/two/three/test.html" + path: "/one/two/three/test.html", }); await readerWriter.write(res); t.deepEqual(readerWriter._virFiles, { - "one/two/three/test.html": res + "one/two/three/test.html": res, }, "Adapter added resource with correct path"); t.deepEqual(Object.keys(readerWriter._virDirs), [ "one/two/three", "one/two", - "one" + "one", ], "Adapter added correct virtual directories"); const dirRes = readerWriter._virDirs["one/two/three"]; @@ -74,22 +74,22 @@ test("Write resource w/o virtual base path", async (t) => { test("Write resource w/ deep virtual base path", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/a/" + virBasePath: "/app/a/", }); const res = createResource({ - path: "/app/a/one/two/three/test.html" + path: "/app/a/one/two/three/test.html", }); await readerWriter.write(res); t.deepEqual(readerWriter._virFiles, { - "one/two/three/test.html": res + "one/two/three/test.html": res, }, "Adapter added resource with correct path"); t.deepEqual(Object.keys(readerWriter._virDirs), [ "one/two/three", "one/two", - "one" + "one", ], "Adapter added correct virtual directories"); const dirRes = readerWriter._virDirs["one/two/three"]; @@ -99,32 +99,32 @@ test("Write resource w/ deep virtual base path", async (t) => { test("Write resource w/ crazy virtual base path", async (t) => { const readerWriter = createAdapter({ - virBasePath: "/app/🐛/" + virBasePath: "/app/🐛/", }); const res = createResource({ - path: "/app/🐛/one\\/2/3️⃣/test" + path: "/app/🐛/one\\/2/3️⃣/test", }); await readerWriter.write(res); t.deepEqual(readerWriter._virFiles, { - "one\\/2/3️⃣/test": res + "one\\/2/3️⃣/test": res, }, "Adapter added resource with correct path"); t.deepEqual(Object.keys(readerWriter._virDirs), [ "one\\/2/3️⃣", "one\\/2", - "one\\" + "one\\", ], "Adapter added correct virtual directories"); }); test("Migration of resource is executed", async (t) => { const writer = createAdapter({ - virBasePath: "/" + virBasePath: "/", }); const resource = createResource({ - path: "/test.js" + path: "/test.js", }); const migrateResourceWriterSpy = sinon.spy(writer, "_migrateResource"); @@ -134,12 +134,12 @@ test("Migration of resource is executed", async (t) => { test("Resource: Change instance after write", async (t) => { const writer = createAdapter({ - virBasePath: "/" + virBasePath: "/", }); const resource = createResource({ path: "/test.js", - string: "MyInitialContent" + string: "MyInitialContent", }); await writer.write(resource); diff --git a/test/lib/fsInterface.ts b/test/lib/fsInterface.ts index 4d00222b..34cd2e4a 100644 --- a/test/lib/fsInterface.ts +++ b/test/lib/fsInterface.ts @@ -39,7 +39,7 @@ function getPath() { test("MemAdapter: readFile", async (t) => { const memAdapter = new MemAdapter({ - virBasePath: "/" + virBasePath: "/", }); const fs = fsInterface(memAdapter); const readFile = promisify(fs.readFile); @@ -47,7 +47,7 @@ test("MemAdapter: readFile", async (t) => { const fsPath = path.join("/", "foo.txt"); await memAdapter.write(new Resource({ path: "/foo.txt", - string: `content of ${fsPath}` + string: `content of ${fsPath}`, })); `content of ${fsPath}`; await assertReadFile(t, readFile, "", fsPath); @@ -56,7 +56,7 @@ test("MemAdapter: readFile", async (t) => { test("FsAdapter: readFile with non-ASCII characters in path", async (t) => { const fsAdapter = new FsAdapter({ virBasePath: "/", - fsBasePath: getPath() + fsBasePath: getPath(), }); const fs = fsInterface(fsAdapter); const readFile = promisify(fs.readFile); @@ -84,7 +84,7 @@ const assertStat = async (t, stat, basepath, filepath) => { test("MemAdapter: stat", async (t) => { const memAdapter = new MemAdapter({ - virBasePath: "/" + virBasePath: "/", }); const fs = fsInterface(memAdapter); const stat = promisify(fs.stat); @@ -92,7 +92,7 @@ test("MemAdapter: stat", async (t) => { const fsPath = path.join("/", "foo.txt"); await memAdapter.write(new Resource({ path: "/foo.txt", - string: `content of ${fsPath}` + string: `content of ${fsPath}`, })); await assertStat(t, stat, "", fsPath); }); @@ -100,7 +100,7 @@ test("MemAdapter: stat", async (t) => { test("FsAdapter: stat", async (t) => { const fsAdapter = new FsAdapter({ virBasePath: "/", - fsBasePath: getPath() + fsBasePath: getPath(), }); const fs = fsInterface(fsAdapter); const stat = promisify(fs.stat); @@ -114,7 +114,7 @@ test("fs: stat", async (t) => { test("MemAdapter: mkdir", async (t) => { const memAdapter = new MemAdapter({ - virBasePath: "/" + virBasePath: "/", }); const fs = fsInterface(memAdapter); const mkdir = promisify(fs.mkdir); diff --git a/test/lib/glob.ts b/test/lib/glob.ts index 4e8c1b61..11273f6f 100644 --- a/test/lib/glob.ts +++ b/test/lib/glob.ts @@ -6,8 +6,8 @@ test.beforeEach((t) => { t.context.readerWriter = { filesystem: new FsAdapter({ fsBasePath: "./test/fixtures/glob", - virBasePath: "/test-resources/" - }) + virBasePath: "/test-resources/", + }), }; }); @@ -55,7 +55,7 @@ test("glob with virtual base path partially matching", async (t) => { const adapter = new FsAdapter({ fsBasePath: "./test/fixtures/glob/application.a", - virBasePath: "/test-resources/application/a/" + virBasePath: "/test-resources/application/a/", }); const resources = await adapter.byGlob("/test-resources/**/*.*"); @@ -106,7 +106,7 @@ test("glob with multiple patterns", async (t) => { "/test-resources/application.b/webapp/i18n/i18n_de.properties", "/test-resources/application.b/webapp/embedded/i18n/i18n_de.properties", "/test-resources/application.b/ui5.yaml", - "/test-resources/application.a/ui5.yaml" + "/test-resources/application.a/ui5.yaml", ]; matchGlobResult(t, resources, expectedResources); @@ -130,7 +130,7 @@ test("glob two specific filetype (yaml and js)", async (t) => { const expectedResources = [ "/test-resources/application.a/webapp/test.js", "/test-resources/application.b/ui5.yaml", - "/test-resources/application.a/ui5.yaml" + "/test-resources/application.a/ui5.yaml", ]; matchGlobResult(t, resources, expectedResources); @@ -141,7 +141,7 @@ test("glob only a specific filetype (json) with exclude pattern", async (t) => { const resources = await t.context.readerWriter.filesystem.byGlob([ "/**/*.json", - "!/**/*package.json" + "!/**/*package.json", ]); resources.forEach((res) => { @@ -155,7 +155,7 @@ test("glob only a specific filetype (json) with multiple exclude pattern", async const resources = await t.context.readerWriter.filesystem.byGlob([ "/**/*.json", "!/**/*package.json", - "!/**/embedded/manifest.json" + "!/**/embedded/manifest.json", ]); matchGlobResult(t, resources, ["/test-resources/application.b/webapp/manifest.json"]); @@ -203,14 +203,14 @@ test("glob with multiple patterns with static exclude", async (t) => { virBasePath: "/test-resources/", excludes: [ "/test-resources/application.b/**", - "!/test-resources/application.b/**/manifest.json" - ] + "!/test-resources/application.b/**/manifest.json", + ], }).byGlob(["/**/*.yaml", "/test-resources/**/i18n_de.properties"]); const expectedResources = [ "/test-resources/application.a/ui5.yaml", "/test-resources/application.b/webapp/manifest.json", - "/test-resources/application.b/webapp/embedded/manifest.json" + "/test-resources/application.b/webapp/embedded/manifest.json", ]; matchGlobResult(t, resources, expectedResources); }); @@ -403,4 +403,3 @@ test("glob with multiple patterns with static exclude", async (t) => { // const matches = await glob([""], opt); // t.deepEqual(matches.length, 23, "Resources should match"); // }); - diff --git a/test/lib/package-exports.ts b/test/lib/package-exports.ts index 13201c3d..bf8b0fba 100644 --- a/test/lib/package-exports.ts +++ b/test/lib/package-exports.ts @@ -19,60 +19,60 @@ test("check number of exports", (t) => { [ { exportedSpecifier: "@ui5/fs/adapters/AbstractAdapter", - mappedModule: "../../lib/adapters/AbstractAdapter.js" + mappedModule: "../../lib/adapters/AbstractAdapter.js", }, { exportedSpecifier: "@ui5/fs/adapters/FileSystem", - mappedModule: "../../lib/adapters/FileSystem.js" + mappedModule: "../../lib/adapters/FileSystem.js", }, { exportedSpecifier: "@ui5/fs/adapters/Memory", - mappedModule: "../../lib/adapters/Memory.js" + mappedModule: "../../lib/adapters/Memory.js", }, { exportedSpecifier: "@ui5/fs/AbstractReader", - mappedModule: "../../lib/AbstractReader.js" + mappedModule: "../../lib/AbstractReader.js", }, { exportedSpecifier: "@ui5/fs/AbstractReaderWriter", - mappedModule: "../../lib/AbstractReaderWriter.js" + mappedModule: "../../lib/AbstractReaderWriter.js", }, { exportedSpecifier: "@ui5/fs/DuplexCollection", - mappedModule: "../../lib/DuplexCollection.js" + mappedModule: "../../lib/DuplexCollection.js", }, { exportedSpecifier: "@ui5/fs/fsInterface", - mappedModule: "../../lib/fsInterface.js" + mappedModule: "../../lib/fsInterface.js", }, { exportedSpecifier: "@ui5/fs/ReaderCollection", - mappedModule: "../../lib/ReaderCollection.js" + mappedModule: "../../lib/ReaderCollection.js", }, { exportedSpecifier: "@ui5/fs/ReaderCollectionPrioritized", - mappedModule: "../../lib/ReaderCollectionPrioritized.js" + mappedModule: "../../lib/ReaderCollectionPrioritized.js", }, { exportedSpecifier: "@ui5/fs/readers/Filter", - mappedModule: "../../lib/readers/Filter.js" + mappedModule: "../../lib/readers/Filter.js", }, { exportedSpecifier: "@ui5/fs/readers/Link", - mappedModule: "../../lib/readers/Link.js" + mappedModule: "../../lib/readers/Link.js", }, { exportedSpecifier: "@ui5/fs/Resource", - mappedModule: "../../lib/Resource.js" + mappedModule: "../../lib/Resource.js", }, { exportedSpecifier: "@ui5/fs/resourceFactory", - mappedModule: "../../lib/resourceFactory.js" + mappedModule: "../../lib/resourceFactory.js", }, // Internal modules (only to be used by @ui5/* packages) { exportedSpecifier: "@ui5/fs/internal/ResourceTagCollection", - mappedModule: "../../lib/ResourceTagCollection.js" + mappedModule: "../../lib/ResourceTagCollection.js", }, ].forEach(({exportedSpecifier, mappedModule}) => { test(`${exportedSpecifier}`, async (t) => { diff --git a/test/lib/readers/Filter.ts b/test/lib/readers/Filter.ts index c48264b4..5550ecf5 100644 --- a/test/lib/readers/Filter.ts +++ b/test/lib/readers/Filter.ts @@ -4,19 +4,19 @@ import Filter from "../../../lib/readers/Filter.js"; test("_byGlob: Basic filter", async (t) => { const abstractReader = { - _byGlob: sinon.stub().returns(Promise.resolve(["resource a", "resource b"])) + _byGlob: sinon.stub().returns(Promise.resolve(["resource a", "resource b"])), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new Filter({ reader: abstractReader, - callback: function(resource) { + callback: function (resource) { if (resource === "resource a") { return false; } return true; - } + }, }); const resources = await readerCollection._byGlob("anyPattern", {}, trace); @@ -25,19 +25,19 @@ test("_byGlob: Basic filter", async (t) => { test("_byPath: Negative filter", async (t) => { const abstractReader = { - _byPath: sinon.stub().returns(Promise.resolve("resource a")) + _byPath: sinon.stub().returns(Promise.resolve("resource a")), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new Filter({ reader: abstractReader, - callback: function(resource) { + callback: function (resource) { if (resource === "resource a") { return false; } return true; - } + }, }); const resource = await readerCollection._byPath("anyPattern", {}, trace); @@ -46,19 +46,19 @@ test("_byPath: Negative filter", async (t) => { test("_byPath: Positive filter", async (t) => { const abstractReader = { - _byPath: sinon.stub().returns(Promise.resolve("resource b")) + _byPath: sinon.stub().returns(Promise.resolve("resource b")), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new Filter({ reader: abstractReader, - callback: function(resource) { + callback: function (resource) { if (resource === "resource a") { return false; } return true; - } + }, }); const resource = await readerCollection._byPath("anyPattern", {}, trace); diff --git a/test/lib/readers/Link.ts b/test/lib/readers/Link.ts index 01abc5d6..2498b923 100644 --- a/test/lib/readers/Link.ts +++ b/test/lib/readers/Link.ts @@ -5,23 +5,23 @@ import ResourceFacade from "../../../lib/ResourceFacade.js"; test("_byGlob: Basic Link", async (t) => { const dummyResourceA = { - getPath: () => "/resources/some/lib/FileA.js" + getPath: () => "/resources/some/lib/FileA.js", }; const dummyResourceB = { - getPath: () => "/resources/some/lib/dir/FileB.js" + getPath: () => "/resources/some/lib/dir/FileB.js", }; const abstractReader = { - _byGlob: sinon.stub().resolves([dummyResourceA, dummyResourceB]) + _byGlob: sinon.stub().resolves([dummyResourceA, dummyResourceB]), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new Link({ reader: abstractReader, pathMapping: { linkPath: `/`, - targetPath: `/resources/some/lib/` - } + targetPath: `/resources/some/lib/`, + }, }); const options = "options"; const resources = await readerCollection._byGlob("anyPattern", options, trace); @@ -46,17 +46,17 @@ test("_byGlob: Basic Link", async (t) => { test("_byGlob: Complex pattern", async (t) => { const abstractReader = { - _byGlob: sinon.stub().resolves([]) + _byGlob: sinon.stub().resolves([]), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new Link({ reader: abstractReader, pathMapping: { linkPath: `/`, - targetPath: `/resources/some/lib/` - } + targetPath: `/resources/some/lib/`, + }, }); const options = "options"; @@ -76,17 +76,17 @@ test("_byGlob: Complex pattern", async (t) => { test("_byGlob: Request prefixed with target path", async (t) => { const abstractReader = { - _byGlob: sinon.stub().resolves([]) + _byGlob: sinon.stub().resolves([]), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new Link({ reader: abstractReader, pathMapping: { linkPath: `/my/lib/`, - targetPath: `/some/lib/` - } + targetPath: `/some/lib/`, + }, }); const options = "options"; const resources = await readerCollection._byGlob("/some/lib/dir/**", options, trace); @@ -104,17 +104,17 @@ test("_byGlob: Request prefixed with target path", async (t) => { test("_byGlob: Request prefixed with link path", async (t) => { const abstractReader = { - _byGlob: sinon.stub().resolves([]) + _byGlob: sinon.stub().resolves([]), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new Link({ reader: abstractReader, pathMapping: { linkPath: `/my/lib/`, - targetPath: `/some/lib/` - } + targetPath: `/some/lib/`, + }, }); const options = "options"; const resources = await readerCollection._byGlob("/my/lib/dir/**", options, trace); @@ -132,20 +132,20 @@ test("_byGlob: Request prefixed with link path", async (t) => { test("_byPath: Basic Link", async (t) => { const dummyResource = { - getPath: () => "/resources/some/lib/dir/File.js" + getPath: () => "/resources/some/lib/dir/File.js", }; const abstractReader = { - _byPath: sinon.stub().resolves(dummyResource) + _byPath: sinon.stub().resolves(dummyResource), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new Link({ reader: abstractReader, pathMapping: { linkPath: `/`, - targetPath: `/resources/some/lib/` - } + targetPath: `/resources/some/lib/`, + }, }); const options = "options"; const resource = await readerCollection._byPath("/dir/File.js", options, trace); @@ -165,20 +165,20 @@ test("_byPath: Basic Link", async (t) => { test("_byPath: Rewrite on same level", async (t) => { const dummyResource = { - getPath: () => "/some/lib/dir/File.js" + getPath: () => "/some/lib/dir/File.js", }; const abstractReader = { - _byPath: sinon.stub().resolves(dummyResource) + _byPath: sinon.stub().resolves(dummyResource), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new Link({ reader: abstractReader, pathMapping: { linkPath: `/my/lib/`, - targetPath: `/some/lib/` - } + targetPath: `/some/lib/`, + }, }); const options = "options"; const resource = await readerCollection._byPath("/my/lib/dir/File.js", options, trace); @@ -198,17 +198,17 @@ test("_byPath: Rewrite on same level", async (t) => { test("_byPath: No resource found", async (t) => { const abstractReader = { - _byPath: sinon.stub().resolves(null) + _byPath: sinon.stub().resolves(null), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new Link({ reader: abstractReader, pathMapping: { linkPath: `/`, - targetPath: `/some/lib/` - } + targetPath: `/some/lib/`, + }, }); const options = "options"; const resource = await readerCollection._byPath("/dir/File.js", options, trace); @@ -226,17 +226,17 @@ test("_byPath: No resource found", async (t) => { test("_byPath: Request different prefix", async (t) => { const abstractReader = { - _byPath: sinon.stub() + _byPath: sinon.stub(), }; const trace = { - collection: sinon.spy() + collection: sinon.spy(), }; const readerCollection = new Link({ reader: abstractReader, pathMapping: { linkPath: `/my/lib/`, - targetPath: `/some/lib/` - } + targetPath: `/some/lib/`, + }, }); const options = "options"; const resource = await readerCollection._byPath("/some/lib/dir/File.js", options, trace); @@ -252,7 +252,7 @@ test("Missing attributes", (t) => { pathMapping: { linkPath: `/`, targetPath: `/`, - } + }, }); }); t.is(err.message, `Missing parameter "reader"`, @@ -260,7 +260,7 @@ test("Missing attributes", (t) => { err = t.throws(() => { new Link({ - reader: abstractReader + reader: abstractReader, }); }); t.is(err.message, `Missing parameter "pathMapping"`, @@ -271,7 +271,7 @@ test("Missing attributes", (t) => { reader: abstractReader, pathMapping: { targetPath: `/`, - } + }, }); }); t.is(err.message, `Path mapping is missing attribute "linkPath"`, @@ -282,7 +282,7 @@ test("Missing attributes", (t) => { reader: abstractReader, pathMapping: { linkPath: `/`, - } + }, }); }); t.is(err.message, `Path mapping is missing attribute "targetPath"`, @@ -294,7 +294,7 @@ test("Missing attributes", (t) => { pathMapping: { linkPath: `/path`, targetPath: `/`, - } + }, }); }); t.is(err.message, `Link path must end with a slash: /path`, @@ -306,7 +306,7 @@ test("Missing attributes", (t) => { pathMapping: { linkPath: `/`, targetPath: `/path`, - } + }, }); }); t.is(err.message, `Target path must end with a slash: /path`, diff --git a/test/lib/resourceFactory.ts b/test/lib/resourceFactory.ts index c535ff90..f0c1df45 100644 --- a/test/lib/resourceFactory.ts +++ b/test/lib/resourceFactory.ts @@ -15,7 +15,7 @@ test("prefixGlobPattern", (t) => { prefixGlobPattern("{/sub-directory-1/,/sub-directory-2/}**", "/pony/path/a"), [ "/pony/path/a/sub-directory-1/**", - "/pony/path/a/sub-directory-2/**" + "/pony/path/a/sub-directory-2/**", ], "GLOBs correctly prefixed"); @@ -50,9 +50,9 @@ test("createAdapter: FS Adapter", async (t) => { fsBasePath: "./test/fixtures/application.a/webapp", virBasePath: "/resources/app/", project: { - getName: () => "my.project" + getName: () => "my.project", }, - excludes: ["**/*.html"] + excludes: ["**/*.html"], }); t.true(adapter instanceof FileSystem, "Returned a FileSystem adapter"); @@ -66,20 +66,20 @@ test("createAdapter: Memory", async (t) => { const adapter = createAdapter({ virBasePath: "/resources/app/", project: { - getName: () => "my.project" + getName: () => "my.project", }, - excludes: ["**/*.html"] + excludes: ["**/*.html"], }); t.true(adapter instanceof Memory, "Returned a Memory adapter"); const resource1 = createResource({ - path: "/resources/app/File.js" + path: "/resources/app/File.js", }); await adapter.write(resource1); const resource2 = createResource({ - path: "/resources/app/index.html" + path: "/resources/app/index.html", }); await adapter.write(resource2); @@ -94,7 +94,7 @@ test("createReader: application project", async (t) => { virBasePath: "/resources/app/", project: { getName: () => "my.project", - getType: () => "application" + getType: () => "application", }, excludes: [ "**/*.html", @@ -102,9 +102,9 @@ test("createReader: application project", async (t) => { "/test/**", "test/**", "!/resources/app/test/**", - "!/test/**/*.html" + "!/test/**/*.html", ], - name: "reader name" + name: "reader name", }); t.true(reader instanceof ReaderCollection, "Returned a ReaderCollection"); @@ -130,16 +130,16 @@ test("createReader: library project", async (t) => { virBasePath: "/resources/lib/", project: { getName: () => "my.project", - getType: () => "library" + getType: () => "library", }, excludes: [ "**/*.html", "/resources/lib/dir/**", "/test-resources/lib/dir/**", "/test/**", - "test/**" + "test/**", ], - name: "reader name" + name: "reader name", }); t.true(reader instanceof ReaderCollection, "Returned a ReaderCollection"); @@ -167,9 +167,9 @@ test("createReader: No project", async (t) => { "/resources/app/dir/**", "/test-resources/app/dir/**", "/test/**", - "test/**" + "test/**", ], - name: "reader name" + name: "reader name", }); t.true(reader instanceof ReaderCollection, "Returned a ReaderCollection"); @@ -184,7 +184,7 @@ test("createReader: No project", async (t) => { "/resources/app/dir/**", "/test-resources/app/dir/**", "/test/**", - "test/**" + "test/**", ], "Excludes do not get prefixed."); }); @@ -192,10 +192,10 @@ test("createReader: Throw error missing 'fsBasePath'", (t) => { const error = t.throws(() => createReader({ virBasePath: "/resources/app/", project: { - getName: () => "my.project" + getName: () => "my.project", }, excludes: ["**/*.html"], - name: "reader name" + name: "reader name", })); t.is(error.message, "Unable to create reader: Missing parameter \"fsBasePath\""); }); @@ -204,22 +204,22 @@ test("createReaderCollection", async (t) => { const adapter = createAdapter({ virBasePath: "/resources/app/", project: { - getName: () => "my.project" + getName: () => "my.project", }, - excludes: ["**/*.html"] + excludes: ["**/*.html"], }); const resource1 = createResource({ - path: "/resources/app/File.js" + path: "/resources/app/File.js", }); const resource2 = createResource({ - path: "/resources/app/index.html" + path: "/resources/app/index.html", }); await adapter.write(resource1); await adapter.write(resource2); const reader = createReaderCollection({ name: "reader name", - readers: [adapter] + readers: [adapter], }); t.true(reader instanceof ReaderCollection, "Returned a ReaderCollection"); t.is(reader._name, "reader name", "Reader has correct name"); @@ -234,22 +234,22 @@ test("createReaderCollectionPrioritized", async (t) => { const adapter = createAdapter({ virBasePath: "/resources/app/", project: { - getName: () => "my.project" + getName: () => "my.project", }, - excludes: ["**/*.html"] + excludes: ["**/*.html"], }); const resource1 = createResource({ - path: "/resources/app/File.js" + path: "/resources/app/File.js", }); const resource2 = createResource({ - path: "/resources/app/index.html" + path: "/resources/app/index.html", }); await adapter.write(resource1); await adapter.write(resource2); const reader = createReaderCollectionPrioritized({ name: "reader name", - readers: [adapter] + readers: [adapter], }); t.true(reader instanceof ReaderCollectionPrioritized, "Returned a ReaderCollection"); t.is(reader._name, "reader name", "Reader has correct name"); @@ -264,28 +264,28 @@ test("createWriterCollection", async (t) => { const adapter1 = createAdapter({ virBasePath: "/", project: { - getName: () => "my.project" - } + getName: () => "my.project", + }, }); const adapter2 = createAdapter({ virBasePath: "/", project: { - getName: () => "my.other.project" - } + getName: () => "my.other.project", + }, }); const resource1 = createResource({ - path: "/resources/app/File.js" + path: "/resources/app/File.js", }); const resource2 = createResource({ - path: "/resources/app2/index.html" + path: "/resources/app2/index.html", }); const writerCollection = createWriterCollection({ name: "writer collection name", writerMapping: { "/resources/app/": adapter1, - "/resources/app2/": adapter2 - } + "/resources/app2/": adapter2, + }, }); t.true(writerCollection instanceof WriterCollection, "Returned a ReaderCollection"); await writerCollection.write(resource1); @@ -305,25 +305,25 @@ test("createWorkspace", async (t) => { fsBasePath: "./test/fixtures/application.a/webapp", virBasePath: "/resources/app/", project: { - getName: () => "my.project" - } + getName: () => "my.project", + }, }); const readerWriter = createAdapter({ virBasePath: "/", project: { - getName: () => "my.other.project" - } + getName: () => "my.other.project", + }, }); const writerCollection = createWorkspace({ name: "writer collection name", reader, - writer: readerWriter + writer: readerWriter, }); t.true(writerCollection instanceof DuplexCollection, "Returned a ReaderCollection"); const resource1 = createResource({ - path: "/resources/app/File.js" + path: "/resources/app/File.js", }); await writerCollection.write(resource1); @@ -339,14 +339,13 @@ test("createWorkspace: Without writer", async (t) => { fsBasePath: "./test/fixtures/application.a/webapp", virBasePath: "/resources/app/", project: { - getName: () => "my.project" - } + getName: () => "my.project", + }, }); const writerCollection = createWorkspace({ name: "writer collection name", - reader + reader, }); t.true(writerCollection instanceof DuplexCollection, "Returned a ReaderCollection"); t.true(writerCollection._writer instanceof Memory, "Internal Writer is created and a MemAdapter"); }); - diff --git a/test/lib/resources.ts b/test/lib/resources.ts index 64b861c5..2bd3f1c8 100644 --- a/test/lib/resources.ts +++ b/test/lib/resources.ts @@ -40,14 +40,14 @@ async function fileEqual(t, actual, expected) { Always make sure that every test writes to a separate file! By default, tests are running concurrent. */ test(adapter + - ": Get resource from application.a (/index.html) and write it to /dest/ using a ReadableStream", async (t) => { + ": Get resource from application.a (/index.html) and write it to /dest/ using a ReadableStream", async (t) => { const source = await getAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }); const dest = await getAdapter({ fsBasePath: "./test/tmp/readerWriters/application.a/simple-read-write", - virBasePath: "/dest/" + virBasePath: "/dest/", }); // Get resource from one readerWriter @@ -73,12 +73,12 @@ async function fileEqual(t, actual, expected) { test(adapter + ": Create resource, write and change content", async (t) => { const dest = await getAdapter({ fsBasePath: "./test/tmp/writer/", - virBasePath: "/dest/writer/" + virBasePath: "/dest/writer/", }); const resource = createResource({ path: "/dest/writer/content/test.js", - string: "MyInitialContent" + string: "MyInitialContent", }); await dest.write(resource); @@ -103,12 +103,12 @@ async function fileEqual(t, actual, expected) { test(adapter + ": Create resource, write and change path", async (t) => { const dest = await getAdapter({ fsBasePath: "./test/tmp/writer/", - virBasePath: "/dest/writer/" + virBasePath: "/dest/writer/", }); const resource = createResource({ path: "/dest/writer/path/test.js", - string: "MyInitialContent" + string: "MyInitialContent", }); await dest.write(resource); @@ -137,16 +137,16 @@ async function fileEqual(t, actual, expected) { }); test(adapter + - ": Create a resource with a path different from the path configured in the adapter", async (t) => { + ": Create a resource with a path different from the path configured in the adapter", async (t) => { t.pass(2); const dest = await getAdapter({ fsBasePath: "./test/tmp/writer/", - virBasePath: "/dest2/writer/" + virBasePath: "/dest2/writer/", }); const resource = createResource({ path: "/dest2/tmp/test.js", - string: "MyContent" + string: "MyContent", }); const error = await t.throwsAsync(dest.write(resource)); @@ -157,16 +157,16 @@ async function fileEqual(t, actual, expected) { }); test(adapter + - ": Create a resource with a path above the path configured in the adapter", async (t) => { + ": Create a resource with a path above the path configured in the adapter", async (t) => { t.pass(2); const dest = await getAdapter({ fsBasePath: "./test/tmp/writer/", - virBasePath: "/dest2/writer/" + virBasePath: "/dest2/writer/", }); const resource = createResource({ path: "/dest2/test.js", - string: "MyContent" + string: "MyContent", }); const error = await t.throwsAsync(dest.write(resource)); @@ -177,16 +177,16 @@ async function fileEqual(t, actual, expected) { }); test(adapter + - ": Create a resource with a path resolving outside the path configured in the adapter", async (t) => { + ": Create a resource with a path resolving outside the path configured in the adapter", async (t) => { t.pass(2); const dest = await getAdapter({ fsBasePath: "./test/tmp/writer/", - virBasePath: "/dest/writer/" + virBasePath: "/dest/writer/", }); const resource = createResource({ path: "/dest/writer/../relative.js", - string: "MyContent" + string: "MyContent", }); // Resource will already resolve relative path segments t.is(resource.getPath(), "/dest/relative.js", "Resource path resolved"); @@ -198,20 +198,20 @@ async function fileEqual(t, actual, expected) { await t.throwsAsync(dest.write(resource), { message: "Failed to write resource with virtual path '/dest/writer/../relative.js': " + - "Path must start with the configured virtual base path of the adapter. Base path: '/dest/writer/'" + "Path must start with the configured virtual base path of the adapter. Base path: '/dest/writer/'", }, "Threw with expected error message"); }); test(adapter + ": Filter resources", async (t) => { const source = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/app/" + virBasePath: "/app/", }); const filteredSource = createFilterReader({ reader: source, callback: (resource) => { return resource.getPath().endsWith(".js"); - } + }, }); const sourceResources = await source.byGlob("**"); t.is(sourceResources.length, 2, "Found two resources in source"); @@ -225,11 +225,11 @@ async function fileEqual(t, actual, expected) { test(adapter + ": Flatten resources", async (t) => { const source = await getAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/resources/app/" + virBasePath: "/resources/app/", }); const transformedSource = createFlatReader({ reader: source, - namespace: "app" + namespace: "app", }); const resources = await transformedSource.byGlob("**/*.js"); @@ -240,14 +240,14 @@ async function fileEqual(t, actual, expected) { test(adapter + ": Link resources", async (t) => { const source = await getAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", - virBasePath: "/resources/app/" + virBasePath: "/resources/app/", }); const transformedSource = createLinkReader({ reader: source, pathMapping: { linkPath: "/wow/this/is/a/beautiful/path/just/wow/", - targetPath: "/resources/" - } + targetPath: "/resources/", + }, }); const resources = await transformedSource.byGlob("**/*.js"); diff --git a/test/lib/tracing/traceSummary.ts b/test/lib/tracing/traceSummary.ts index 94bbd746..9dda79d3 100644 --- a/test/lib/tracing/traceSummary.ts +++ b/test/lib/tracing/traceSummary.ts @@ -2,17 +2,17 @@ import test from "ava"; import sinon from "sinon"; import esmock from "esmock"; -async function createMock(t, isLevelEnabled=true) { +async function createMock(t, isLevelEnabled = true) { t.context.loggerStub = { silly: sinon.stub(), isLevelEnabled: () => { return isLevelEnabled; - } + }, }; t.context.traceSummary = await esmock("../../../lib/tracing/traceSummary.js", { "@ui5/logger": { - getLogger: sinon.stub().returns(t.context.loggerStub) - } + getLogger: sinon.stub().returns(t.context.loggerStub), + }, }); return t.context; } From 9d840f12bca1207b902cb8c366e2799df9b34809 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 10:33:56 +0300 Subject: [PATCH 05/69] refactor: Ignore generated code --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 052409d7..ef2f666f 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,9 @@ build/Release node_modules jspm_packages +# TypeScript cache +*.tsbuildinfo + # Optional npm cache directory .npm @@ -60,3 +63,6 @@ deploy_key # Custom directories test/tmp/ jsdocs/ + +# Generated code +/lib/ From 53dbae3e5846242c3e2044d703c1a12f3b4cbf25 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 12:40:40 +0300 Subject: [PATCH 06/69] refactor: Migrate Resource.ts --- .gitignore | 2 +- src/Resource.ts | 149 ++++++++++++++++++++--------------- src/utils/mock-projects.d.ts | 9 +++ src/utils/tsUtils.ts | 3 + 4 files changed, 98 insertions(+), 65 deletions(-) create mode 100644 src/utils/mock-projects.d.ts create mode 100644 src/utils/tsUtils.ts diff --git a/.gitignore b/.gitignore index ef2f666f..39804491 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,4 @@ test/tmp/ jsdocs/ # Generated code -/lib/ +lib/ diff --git a/src/Resource.ts b/src/Resource.ts index bcae1a32..159ed7ee 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -1,10 +1,42 @@ import stream from "node:stream"; import clone from "clone"; import posixPath from "node:path/posix"; +import {Buffer} from "node:buffer"; +import type {Stats} from "node:fs"; +import type {Project} from "@ui5/project/specifications/Project"; +import {isString} from "./utils/tsUtils.js"; const fnTrue = () => true; const fnFalse = () => false; -const ALLOWED_SOURCE_METADATA_KEYS = ["adapter", "fsPath", "contentModified"]; + +enum ALLOWED_SOURCE_METADATA_KEYS { + ADAPTER = "adapter", + FS_PATH = "fsPath", + CONTENT_MODIFIED = "contentModified", +}; + +/** + * Function for dynamic creation of content streams + * + * @public + * @callback @ui5/fs/Resource~createStream + * @returns {stream.Readable} A readable stream of a resources content + */ +type Resource_CreateReadableStream = () => stream.Readable; + +type Resource_sourceMetadata = Partial>; + +interface Resource_Options { + path: string; + statInfo: Stats; + buffer?: Buffer; + string?: string; + createStream?: Resource_CreateReadableStream; + stream?: stream.Readable; + project?: Project; sourceMetadata: Resource_sourceMetadata; +}; + +interface Tree {[x: string]: object | Tree}; /** * Resource. UI5 Tooling specific representation of a file's content and metadata @@ -15,26 +47,18 @@ const ALLOWED_SOURCE_METADATA_KEYS = ["adapter", "fsPath", "contentModified"]; */ class Resource { #project; - #buffer; - #buffering; - #collections; - #contentDrained; - #createStream; - #name; - #path; - #sourceMetadata; - #statInfo; - #stream; - #streamDrained; - #isModified; - - /** - * Function for dynamic creation of content streams - * - * @public - * @callback @ui5/fs/Resource~createStream - * @returns {stream.Readable} A readable stream of a resources content - */ + #buffer: Buffer | null | undefined; + #buffering: Promise | null | undefined; + #collections: string[]; + #contentDrained: boolean | undefined; + #createStream: Resource_CreateReadableStream | null | undefined; + #name!: string; + #path!: string; + #sourceMetadata: Resource_sourceMetadata; + #statInfo: Stats; + #stream: stream.Readable | null | undefined; + #streamDrained: boolean | undefined; + #isModified: boolean; /** * @@ -58,12 +82,13 @@ class Resource { * Some information may be set by an adapter to store information for later retrieval. Also keeps track of whether * a resource content has been modified since it has been read from a source */ - constructor({path, statInfo, buffer, string, createStream, stream, project, sourceMetadata}) { + constructor({path, statInfo, buffer, string, createStream, stream, project, sourceMetadata}: Resource_Options + ) { if (!path) { throw new Error("Unable to create Resource: Missing parameter 'path'"); } - if (buffer && createStream || buffer && string || string && createStream || buffer && stream || - string && stream || createStream && stream) { + if ((buffer && createStream) || (buffer && string) || (string && createStream) || (buffer && stream) || + (string && stream) || (createStream && stream)) { throw new Error("Unable to create Resource: Please set only one content parameter. " + "'buffer', 'string', 'stream' or 'createStream'"); } @@ -74,14 +99,9 @@ class Resource { } for (const metadataKey in sourceMetadata) { // Also check prototype - if (!ALLOWED_SOURCE_METADATA_KEYS.includes(metadataKey)) { + if (!(metadataKey in ALLOWED_SOURCE_METADATA_KEYS)) { throw new Error(`Parameter 'sourceMetadata' contains an illegal attribute: ${metadataKey}`); } - if (!["string", "boolean"].includes(typeof sourceMetadata[metadataKey])) { - throw new Error( - `Attribute '${metadataKey}' of parameter 'sourceMetadata' ` + - `must be of type "string" or "boolean"`); - } } } @@ -124,7 +144,7 @@ class Resource { } else if (buffer) { // Use private setter, not to accidentally set any modified flags this.#setBuffer(buffer); - } else if (typeof string === "string" || string instanceof String) { + } else if (isString(string)) { // Use private setter, not to accidentally set any modified flags this.#setBuffer(Buffer.from(string, "utf8")); } @@ -139,7 +159,7 @@ class Resource { * @public * @returns {Promise} Promise resolving with a buffer of the resource content. */ - async getBuffer() { + async getBuffer(): Promise { if (this.#contentDrained) { throw new Error(`Content of Resource ${this.#path} has been drained. ` + "This might be caused by requesting resource content after a content stream has been " + @@ -160,13 +180,13 @@ class Resource { * @public * @param {Buffer} buffer Buffer instance */ - setBuffer(buffer) { + setBuffer(buffer: Buffer) { this.#sourceMetadata.contentModified = true; this.#isModified = true; this.#setBuffer(buffer); } - #setBuffer(buffer) { + #setBuffer(buffer: Buffer) { this.#createStream = null; // if (this.#stream) { // TODO this may cause strange issues // this.#stream.destroy(); @@ -183,7 +203,7 @@ class Resource { * @public * @returns {Promise} Promise resolving with the resource content. */ - getString() { + getString(): Promise { if (this.#contentDrained) { return Promise.reject(new Error(`Content of Resource ${this.#path} has been drained. ` + "This might be caused by requesting resource content after a content stream has been " + @@ -198,7 +218,7 @@ class Resource { * @public * @param {string} string Resource content */ - setString(string) { + setString(string: string) { this.setBuffer(Buffer.from(string, "utf8")); } @@ -213,7 +233,7 @@ class Resource { * @public * @returns {stream.Readable} Readable stream for the resource content. */ - getStream() { + getStream(): stream.Readable { if (this.#contentDrained) { throw new Error(`Content of Resource ${this.#path} has been drained. ` + "This might be caused by requesting resource content after a content stream has been " + @@ -249,7 +269,7 @@ class Resource { * @param {stream.Readable|@ui5/fs/Resource~createStream} stream Readable stream of the resource content or callback for dynamic creation of a readable stream */ - setStream(stream) { + setStream(stream: stream.Readable | Resource_CreateReadableStream) { this.#isModified = true; this.#sourceMetadata.contentModified = true; @@ -274,8 +294,8 @@ class Resource { * @public * @returns {string} Virtual path of the resource */ - getPath() { - return this.#path; + getPath(): string { + return this.#path ?? ""; } /** @@ -284,7 +304,7 @@ class Resource { * @public * @param {string} path Absolute virtual path of the resource */ - setPath(path) { + setPath(path: string) { path = posixPath.normalize(path); if (!posixPath.isAbsolute(path)) { throw new Error(`Unable to set resource path: Path must be absolute: ${path}`); @@ -299,7 +319,7 @@ class Resource { * @public * @returns {string} Name of the resource */ - getName() { + getName(): string { return this.#name; } @@ -313,7 +333,7 @@ class Resource { * @returns {fs.Stats|object} Instance of [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} * or similar object */ - getStatInfo() { + getStatInfo(): Stats { return this.#statInfo; } @@ -323,7 +343,7 @@ class Resource { * @see {TypedArray#byteLength} * @returns {Promise} size in bytes, 0 if there is no content yet */ - async getSize() { + async getSize(): Promise { // if resource does not have any content it should have 0 bytes if (!this.#buffer && !this.#createStream && !this.#stream) { return 0; @@ -337,7 +357,7 @@ class Resource { * * @param {string} name Resource collection name */ - pushCollection(name) { + pushCollection(name: string) { this.#collections.push(name); } @@ -347,13 +367,13 @@ class Resource { * @public * @returns {Promise<@ui5/fs/Resource>} Promise resolving with the clone */ - async clone() { + async clone(): Promise { const options = await this.#getCloneOptions(); return new Resource(options); } - async #getCloneOptions() { - const options = { + async #getCloneOptions(): Promise { + const options: Resource_Options = { path: this.#path, statInfo: clone(this.#statInfo), sourceMetadata: clone(this.#sourceMetadata), @@ -381,9 +401,9 @@ class Resource { * return a Specification Version-compatible Project interface. * * @public - * @returns {@ui5/project/specifications/Project} Project this resource is associated with + * @returns {@ui5/project/specifications/Project|undefined} Project this resource is associated with */ - getProject() { + getProject(): Project | undefined { return this.#project; } @@ -393,10 +413,10 @@ class Resource { * @public * @param {@ui5/project/specifications/Project} project Project this resource is associated with */ - setProject(project) { + setProject(project: Project) { if (this.#project) { throw new Error(`Unable to assign project ${project.getName()} to resource ${this.#path}: ` + - `Resource is already associated to project ${this.#project}`); + `Resource is already associated to project ${this.#project.getName()}`); } this.#project = project; } @@ -407,7 +427,7 @@ class Resource { * @public * @returns {boolean} True if the resource is associated with a project */ - hasProject() { + hasProject(): boolean { return !!this.#project; } @@ -417,7 +437,7 @@ class Resource { * @public * @returns {boolean} True if the resource's content has been changed */ - isModified() { + isModified(): boolean { return this.#isModified; } @@ -426,13 +446,13 @@ class Resource { * * @returns {object} Trace tree */ - getPathTree() { - const tree = Object.create(null); + getPathTree(): Tree { + const tree = Object.create(null) as Tree; - let pointer = tree[this.#path] = Object.create(null); + let pointer = tree[this.#path] = Object.create(null) as Tree; for (let i = this.#collections.length - 1; i >= 0; i--) { - pointer = pointer[this.#collections[i]] = Object.create(null); + pointer = pointer[this.#collections[i]] = Object.create(null) as Tree; } return tree; @@ -444,7 +464,7 @@ class Resource { * * @returns {object} */ - getSourceMetadata() { + getSourceMetadata(): Resource_sourceMetadata { return this.#sourceMetadata; } @@ -454,7 +474,7 @@ class Resource { * @private * @returns {stream.Readable} Readable stream */ - #getStream() { + #getStream(): stream.Readable { if (this.#streamDrained) { throw new Error(`Content stream of Resource ${this.#path} is flagged as drained.`); } @@ -462,7 +482,7 @@ class Resource { return this.#createStream(); } this.#streamDrained = true; - return this.#stream; + return this.#stream!; } /** @@ -471,14 +491,15 @@ class Resource { * @private * @returns {Promise} Promise resolving with buffer. */ - #getBufferFromStream() { + #getBufferFromStream(): Promise { if (this.#buffering) { // Prevent simultaneous buffering, causing unexpected access to drained stream return this.#buffering; } return this.#buffering = new Promise((resolve, reject) => { const contentStream = this.#getStream(); - const buffers = []; - contentStream.on("data", (data) => { + const buffers: Buffer[] = []; + + contentStream.on("data", (data: Buffer) => { buffers.push(data); }); contentStream.on("error", (err) => { diff --git a/src/utils/mock-projects.d.ts b/src/utils/mock-projects.d.ts new file mode 100644 index 00000000..1b28acd2 --- /dev/null +++ b/src/utils/mock-projects.d.ts @@ -0,0 +1,9 @@ +// TODO: This file is meant only for temp resolve of the UI5 tooling +// dependencies, until they got migrated and we can have the real TS definitions + +declare module "@ui5/project/specifications/Project" { + + export interface Project { + getName: () => string + } +} diff --git a/src/utils/tsUtils.ts b/src/utils/tsUtils.ts new file mode 100644 index 00000000..421cbded --- /dev/null +++ b/src/utils/tsUtils.ts @@ -0,0 +1,3 @@ +export function isString(testString: unknown): testString is string { + return testString instanceof String; +} From a79e79579919fb4923ba7e110af39685df1f6dfb Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 12:41:41 +0300 Subject: [PATCH 07/69] fix: ESLint --- src/utils/mock-projects.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/mock-projects.d.ts b/src/utils/mock-projects.d.ts index 1b28acd2..64da3d59 100644 --- a/src/utils/mock-projects.d.ts +++ b/src/utils/mock-projects.d.ts @@ -3,7 +3,7 @@ declare module "@ui5/project/specifications/Project" { - export interface Project { - getName: () => string + export interface Project { + getName: () => string; } } From 70cd760b3bf1820028521f37719bb04e80d898cc Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 12:42:59 +0300 Subject: [PATCH 08/69] fix: Add dep types --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 965bff83..a6d9c5c3 100644 --- a/package.json +++ b/package.json @@ -129,6 +129,7 @@ "@istanbuljs/nyc-config-typescript": "^1.0.2", "@stylistic/eslint-plugin": "^2.6.4", "@types/node": "^20.11.0", + "@types/pretty-hrtime": "^1.0.3", "@types/sinon": "^17.0.3", "ava": "^6.1.3", "chokidar-cli": "^3.0.0", From 2271848fcf13e09ee32e5ec816f301b0d93d1008 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 13:08:47 +0300 Subject: [PATCH 09/69] refactor: Migrate traceSummary.ts --- src/tracing/traceSummary.ts | 41 +++++++++++++++++++++++++----------- src/utils/mock-projects.d.ts | 9 ++++++++ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/tracing/traceSummary.ts b/src/tracing/traceSummary.ts index 54755515..cac4ff8d 100644 --- a/src/tracing/traceSummary.ts +++ b/src/tracing/traceSummary.ts @@ -2,11 +2,18 @@ import {getLogger} from "@ui5/logger"; const log = getLogger("resources:tracing:total"); import prettyHrtime from "pretty-hrtime"; -const hasOwnProperty = Object.prototype.hasOwnProperty; -let timeoutId; +let timeoutId: NodeJS.Timeout; let active = false; let tracesRunning = 0; -let traceData; +type CollectionsType = T & Record; +let traceData: null | { + startTime: [number, number]; + pathCalls: number; + globCalls: number; + collections: CollectionsType; + traceCalls: number; + timeDiff?: [number, number]; +}; function init() { traceData = { @@ -26,7 +33,12 @@ function reset() { function report() { let report = ""; - const time = prettyHrtime(traceData.timeDiff); + + if (!traceData) { + return; + } + + const time = prettyHrtime(traceData.timeDiff!); const colCount = Object.keys(traceData.collections).length; report += "==========================\n[=> TRACE SUMMARY:\n"; @@ -41,7 +53,7 @@ function report() { report += ` ${colCount} rl-collections involed:\n`; for (const coll in traceData.collections) { - if (hasOwnProperty.call(traceData.collections, coll)) { + if (Object.prototype.hasOwnProperty.call(traceData.collections, coll)) { report += ` ${traceData.collections[coll].calls}x ${coll}\n`; } } @@ -57,15 +69,15 @@ function someTraceStarted() { init(); } tracesRunning++; - traceData.traceCalls++; + traceData!.traceCalls++; if (timeoutId) { clearTimeout(timeoutId); } } -function someTraceEnded() { - return new Promise(function (resolve, reject) { +function someTraceEnded(): Promise { + return new Promise(function (resolve) { if (!active) { resolve(); return; @@ -79,7 +91,7 @@ function someTraceEnded() { if (timeoutId) { clearTimeout(timeoutId); } - traceData.timeDiff = process.hrtime(traceData.startTime); + traceData!.timeDiff = process.hrtime(traceData!.startTime); timeoutId = setTimeout(function () { report(); reset(); @@ -92,17 +104,22 @@ function pathCall() { if (!active) { return; } - traceData.pathCalls++; + if (traceData) { + traceData.pathCalls++; + } } function globCall() { if (!active) { return; } - traceData.globCalls++; + + if (traceData) { + traceData.globCalls++; + } } -function collection(name) { +function collection(name: string) { if (!active) { return; } diff --git a/src/utils/mock-projects.d.ts b/src/utils/mock-projects.d.ts index 64da3d59..15228537 100644 --- a/src/utils/mock-projects.d.ts +++ b/src/utils/mock-projects.d.ts @@ -7,3 +7,12 @@ declare module "@ui5/project/specifications/Project" { getName: () => string; } } + +declare module "@ui5/logger" { + interface logger { + silly(x: string): void + isLevelEnabled(x:string): boolean + } + + export function getLogger(x: string): logger +} From 0be01b786de6db14e6bb3cb4076f14210503335f Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 13:16:30 +0300 Subject: [PATCH 10/69] refactor: Migrate Trace.ts --- src/tracing/Trace.ts | 19 ++++++++++++------- src/tracing/traceSummary.ts | 4 +++- src/utils/mock-projects.d.ts | 6 +++--- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/tracing/Trace.ts b/src/tracing/Trace.ts index a6835be9..a12e5de5 100644 --- a/src/tracing/Trace.ts +++ b/src/tracing/Trace.ts @@ -3,8 +3,7 @@ const log = getLogger("resources:tracing:Trace"); const logGlobs = getLogger("resources:tracing:Trace:globs"); const logPaths = getLogger("resources:tracing:Trace:paths"); import prettyHrtime from "pretty-hrtime"; -import summaryTrace from "./traceSummary.js"; -const hasOwnProperty = Object.prototype.hasOwnProperty; +import summaryTrace, {CollectionsType} from "./traceSummary.js"; /** * Trace @@ -13,7 +12,13 @@ const hasOwnProperty = Object.prototype.hasOwnProperty; * @class */ class Trace { - constructor(name) { + _name!: string; + _startTime!: [number, number]; + _globCalls!: number; + _pathCalls!: number; + _collections!: CollectionsType; + + constructor(name: string) { if (!log.isLevelEnabled("silly")) { return; } @@ -21,7 +26,7 @@ class Trace { this._startTime = process.hrtime(); this._globCalls = 0; this._pathCalls = 0; - this._collections = Object.create(null); + this._collections = Object.create(null) as CollectionsType; summaryTrace.traceStarted(); } @@ -41,7 +46,7 @@ class Trace { summaryTrace.pathCall(); } - collection(name) { + collection(name: string) { if (!log.isLevelEnabled("silly")) { return; } @@ -76,7 +81,7 @@ class Trace { report += ` ${colCount} reader-collections involed:\n`; for (const coll in this._collections) { - if (hasOwnProperty.call(this._collections, coll)) { + if (Object.prototype.hasOwnProperty.call(this._collections, coll)) { report += ` ${this._collections[coll].calls}x ${coll}\n`; } } @@ -90,7 +95,7 @@ class Trace { logPaths.silly(report); } - summaryTrace.traceEnded(); + void summaryTrace.traceEnded(); } } diff --git a/src/tracing/traceSummary.ts b/src/tracing/traceSummary.ts index cac4ff8d..6ad2efd7 100644 --- a/src/tracing/traceSummary.ts +++ b/src/tracing/traceSummary.ts @@ -5,7 +5,9 @@ import prettyHrtime from "pretty-hrtime"; let timeoutId: NodeJS.Timeout; let active = false; let tracesRunning = 0; -type CollectionsType = T & Record; + +export type CollectionsType = T & Record; + let traceData: null | { startTime: [number, number]; pathCalls: number; diff --git a/src/utils/mock-projects.d.ts b/src/utils/mock-projects.d.ts index 15228537..e1fe7736 100644 --- a/src/utils/mock-projects.d.ts +++ b/src/utils/mock-projects.d.ts @@ -10,9 +10,9 @@ declare module "@ui5/project/specifications/Project" { declare module "@ui5/logger" { interface logger { - silly(x: string): void - isLevelEnabled(x:string): boolean + silly(x: string): void; + isLevelEnabled(x: string): boolean; } - export function getLogger(x: string): logger + export function getLogger(x: string): logger; } From 6b71d00de907d1a65336bbf93af557df2ad76477 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 14:41:43 +0300 Subject: [PATCH 11/69] refactor: Migrate AbstractReader --- src/AbstractReader.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index 4cc5309c..5b45df85 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -1,5 +1,6 @@ import randomInt from "random-int"; import Trace from "./tracing/Trace.js"; +import Resource from "./Resource.js"; /** * Abstract resource locator implementing the general API for reading resources @@ -10,13 +11,14 @@ import Trace from "./tracing/Trace.js"; * @alias @ui5/fs/AbstractReader */ class AbstractReader { + _name: string | undefined; /** * The constructor. * * @public * @param {string} name Name of the reader. Typically used for tracing purposes */ - constructor(name) { + constructor(name: string | undefined) { if (new.target === AbstractReader) { throw new TypeError("Class 'AbstractReader' is abstract"); } @@ -28,8 +30,8 @@ class AbstractReader { * * @returns {string} Name of the reader */ - getName() { - return this._name || ``; + getName(): string { + return this._name ?? ``; } /** @@ -47,12 +49,12 @@ class AbstractReader { * @param {boolean} [options.nodir=true] Do not match directories * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - byGlob(virPattern, options = {nodir: true}) { + byGlob(virPattern: string, options = {nodir: true}): Promise { const trace = new Trace(virPattern); - return this._byGlob(virPattern, options, trace).then(function (result) { + return this._byGlob(virPattern, options, trace).then(function (result: Resource[]) { trace.printReport(); return result; - }).then((resources) => { + }).then((resources: Resource[]) => { if (resources.length > 1) { // Pseudo randomize result order to prevent consumers from relying on it: // Swap the first object with a randomly chosen one @@ -74,7 +76,7 @@ class AbstractReader { * @param {boolean} [options.nodir=true] Do not match directories * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - byPath(virPath, options = {nodir: true}) { + byPath(virPath: string, options = {nodir: true}): Promise { const trace = new Trace(virPath); return this._byPath(virPath, options, trace).then(function (resource) { trace.printReport(); @@ -93,7 +95,7 @@ class AbstractReader { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - _byGlob(virPattern, options, trace) { + _byGlob(_virPattern: string | string[], _options: object, _trace: Trace): Promise { throw new Error("Function '_byGlob' is not implemented"); } @@ -107,7 +109,7 @@ class AbstractReader { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - _runGlob(pattern, options, trace) { + _runGlob(_pattern: string, _options: object, _trace: Trace): Promise { throw new Error("Function '_runGlob' is not implemented"); } @@ -121,7 +123,7 @@ class AbstractReader { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - _byPath(virPath, options, trace) { + _byPath(_virPath: string, _options: object, _trace: Trace): Promise { throw new Error("Function '_byPath' is not implemented"); } } From 47da2fc84651bfeb62b78eb4e47ba642f72fd58b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 23 Aug 2024 14:44:02 +0300 Subject: [PATCH 12/69] refactor: Migrate AbstractReaderWriter --- src/AbstractReaderWriter.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/AbstractReaderWriter.ts b/src/AbstractReaderWriter.ts index 9e07da5e..c1eded03 100644 --- a/src/AbstractReaderWriter.ts +++ b/src/AbstractReaderWriter.ts @@ -1,4 +1,5 @@ import AbstractReader from "./AbstractReader.js"; +import Resource from "./Resource.js"; /** * Abstract resource locator implementing the general API for reading and writing resources @@ -16,7 +17,7 @@ class AbstractReaderWriter extends AbstractReader { * @public * @param {string} name Name of the reader/writer. Typically used for tracing purposes */ - constructor(name) { + constructor(name: string | undefined) { if (new.target === AbstractReaderWriter) { throw new TypeError("Class 'AbstractReaderWriter' is abstract"); } @@ -28,8 +29,8 @@ class AbstractReaderWriter extends AbstractReader { * * @returns {string} Name of the reader/writer */ - getName() { - return this._name || ``; + getName(): string { + return this._name ?? ``; } /** @@ -50,7 +51,7 @@ class AbstractReaderWriter extends AbstractReader { * E.g. the final write of a resource after all processing is finished. * @returns {Promise} Promise resolving once data has been written */ - write(resource, options = {drain: false, readOnly: false}) { + write(resource: Resource, options = {drain: false, readOnly: false}): Promise { return this._write(resource, options); } @@ -63,7 +64,7 @@ class AbstractReaderWriter extends AbstractReader { * @param {object} [options] Write options, see above * @returns {Promise} Promise resolving once data has been written */ - _write(resource, options) { + _write(_resource: Resource, _options: object): Promise { throw new Error("Not implemented"); } } From b2bde059a0c008b1a05cf0d03fdff9fd1b4e880f Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Mon, 26 Aug 2024 11:29:19 +0300 Subject: [PATCH 13/69] refactor: Migrate the AbstractAdaptor --- package.json | 1 + src/AbstractReader.ts | 12 ++++--- src/AbstractReaderWriter.ts | 2 +- src/Resource.ts | 27 ++++++++++++++-- src/adapters/AbstractAdapter.ts | 57 +++++++++++++++++++-------------- src/utils/mock-projects.d.ts | 1 + src/utils/tsUtils.ts | 8 +++++ 7 files changed, 76 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index a6d9c5c3..95c7d87b 100644 --- a/package.json +++ b/package.json @@ -128,6 +128,7 @@ "@istanbuljs/esm-loader-hook": "^0.2.0", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@stylistic/eslint-plugin": "^2.6.4", + "@types/micromatch": "^4.0.9", "@types/node": "^20.11.0", "@types/pretty-hrtime": "^1.0.3", "@types/sinon": "^17.0.3", diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index 5b45df85..57f33efe 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -18,7 +18,7 @@ class AbstractReader { * @public * @param {string} name Name of the reader. Typically used for tracing purposes */ - constructor(name: string | undefined) { + constructor(name?: string) { if (new.target === AbstractReader) { throw new TypeError("Class 'AbstractReader' is abstract"); } @@ -95,7 +95,11 @@ class AbstractReader { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - _byGlob(_virPattern: string | string[], _options: object, _trace: Trace): Promise { + _byGlob(_virPattern: string | string[], + _options: { + nodir: boolean + }, + _trace: Trace): Promise { throw new Error("Function '_byGlob' is not implemented"); } @@ -104,12 +108,12 @@ class AbstractReader { * * @abstract * @protected - * @param {string} pattern glob pattern + * @param {string|string[]} pattern glob pattern * @param {object} options glob options * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - _runGlob(_pattern: string, _options: object, _trace: Trace): Promise { + _runGlob(_pattern: string | string[], _options: object, _trace: Trace): Promise { throw new Error("Function '_runGlob' is not implemented"); } diff --git a/src/AbstractReaderWriter.ts b/src/AbstractReaderWriter.ts index c1eded03..58f97ecb 100644 --- a/src/AbstractReaderWriter.ts +++ b/src/AbstractReaderWriter.ts @@ -17,7 +17,7 @@ class AbstractReaderWriter extends AbstractReader { * @public * @param {string} name Name of the reader/writer. Typically used for tracing purposes */ - constructor(name: string | undefined) { + constructor(name?: string) { if (new.target === AbstractReaderWriter) { throw new TypeError("Class 'AbstractReaderWriter' is abstract"); } diff --git a/src/Resource.ts b/src/Resource.ts index 159ed7ee..3ebcc3ab 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -26,18 +26,39 @@ type Resource_CreateReadableStream = () => stream.Readable; type Resource_sourceMetadata = Partial>; -interface Resource_Options { +// TODO: Validate these options. +// Some might be required while others can be optional. +// Different combinations can be ok. +export interface Resource_Options { path: string; - statInfo: Stats; + // It could be a real Stats, but also a Stats like object + statInfo: Partial; buffer?: Buffer; string?: string; createStream?: Resource_CreateReadableStream; stream?: stream.Readable; - project?: Project; sourceMetadata: Resource_sourceMetadata; + project?: Project; + sourceMetadata?: Resource_sourceMetadata; + source?: { + adapter?: "Abstract"; + }; }; interface Tree {[x: string]: object | Tree}; +export interface LegacyResource { + _path: string; + // It could be a real Stats, but also a Stats like object + _statInfo?: Partial; + _source?: { + adapter?: "Abstract"; + }; + _createStream?: Resource_CreateReadableStream; + _stream?: stream.Readable; + _buffer?: Buffer; + _getBufferFromStream: () => Promise; +} + /** * Resource. UI5 Tooling specific representation of a file's content and metadata * diff --git a/src/adapters/AbstractAdapter.ts b/src/adapters/AbstractAdapter.ts index a8c0cabd..506ce3b8 100644 --- a/src/adapters/AbstractAdapter.ts +++ b/src/adapters/AbstractAdapter.ts @@ -4,7 +4,10 @@ const log = getLogger("resources:adapters:AbstractAdapter"); import {minimatch} from "minimatch"; import micromatch from "micromatch"; import AbstractReaderWriter from "../AbstractReaderWriter.js"; -import Resource from "../Resource.js"; +import Resource, {Resource_Options, LegacyResource} from "../Resource.js"; +import type {Project} from "@ui5/project/specifications/Project"; +import Trace from "../tracing/Trace.js"; +import {isLegacyResource} from "../utils/tsUtils.js"; /** * Abstract Resource Adapter @@ -16,6 +19,12 @@ import Resource from "../Resource.js"; * @extends @ui5/fs/AbstractReaderWriter */ class AbstractAdapter extends AbstractReaderWriter { + _virBasePath: string; + _virBaseDir: string; + _excludes: string[]; + _excludesNegated: string[]; + _project: Project; + /** * The constructor * @@ -26,7 +35,8 @@ class AbstractAdapter extends AbstractReaderWriter { * @param {string[]} [parameters.excludes] List of glob patterns to exclude * @param {object} [parameters.project] Experimental, internal parameter. Do not use */ - constructor({virBasePath, excludes = [], project}) { + constructor({virBasePath, excludes = [], project}: + {virBasePath: string; excludes: string[]; project: Project}) { if (new.target === AbstractAdapter) { throw new TypeError("Class 'AbstractAdapter' is abstract"); } @@ -61,7 +71,7 @@ class AbstractAdapter extends AbstractReaderWriter { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - async _byGlob(virPattern, options = {nodir: true}, trace) { + async _byGlob(virPattern: string | string[], options = {nodir: true}, trace: Trace): Promise { const excludes = this._excludesNegated; if (!(virPattern instanceof Array)) { @@ -70,8 +80,8 @@ class AbstractAdapter extends AbstractReaderWriter { // Append static exclude patterns virPattern = Array.prototype.concat.apply(virPattern, excludes); - let patterns = virPattern.map(this._normalizePattern, this); - patterns = Array.prototype.concat.apply([], patterns); + const normalizedPatterns = virPattern.map(this._normalizePattern.bind(this)); + const patterns = Array.prototype.concat.apply([], normalizedPatterns) as string[]; if (patterns.length === 0) { return []; } @@ -103,10 +113,10 @@ class AbstractAdapter extends AbstractReaderWriter { /** * Validate if virtual path should be excluded * - * @param {string} virPath Virtual Path + * @param {string[]} virPath Virtual Path * @returns {boolean} True if path is excluded, otherwise false */ - _isPathExcluded(virPath) { + _isPathExcluded(virPath: string[]) { return micromatch(virPath, this._excludes).length > 0; } @@ -118,7 +128,7 @@ class AbstractAdapter extends AbstractReaderWriter { * @param {string} virPath Virtual Path * @returns {boolean} True if path should be handled */ - _isPathHandled(virPath) { + _isPathHandled(virPath: string) { // Check whether path starts with base path, or equals base directory return virPath.startsWith(this._virBasePath) || virPath === this._virBaseDir; } @@ -130,22 +140,21 @@ class AbstractAdapter extends AbstractReaderWriter { * @param {string} virPattern glob pattern for virtual directory structure * @returns {string[]} A list of normalized glob patterns */ - _normalizePattern(virPattern) { - const that = this; + _normalizePattern(virPattern: string) { const mm = new minimatch.Minimatch(virPattern); const basePathParts = this._virBaseDir.split("/"); - function matchSubset(subset) { + const matchSubset = (subset: (string | typeof minimatch.GLOBSTAR | RegExp | undefined)[]) => { let i; for (i = 0; i < basePathParts.length; i++) { const globPart = subset[i]; if (globPart === undefined) { log.verbose("Ran out of glob parts to match (this should not happen):"); - if (that._project) { // project is optional - log.verbose(`Project: ${that._project.getName()}`); + if (this._project) { // project is optional + log.verbose(`Project: ${this._project.getName()}`); } - log.verbose(`Virtual base path: ${that._virBaseDir}`); + log.verbose(`Virtual base path: ${this._virBaseDir}`); log.verbose(`Pattern to match: ${virPattern}`); log.verbose(`Current subset (tried index ${i}):`); log.verbose(subset); @@ -172,9 +181,9 @@ class AbstractAdapter extends AbstractReaderWriter { return {rootMatch: true}; } return {idx: i}; - } + }; - const resultGlobs = []; + const resultGlobs: string[] = []; for (let i = 0; i < mm.set.length; i++) { const match = matchSubset(mm.set[i]); if (match) { @@ -198,32 +207,32 @@ class AbstractAdapter extends AbstractReaderWriter { return resultGlobs; } - _createResource(parameters) { + _createResource(parameters: Resource_Options) { if (this._project) { parameters.project = this._project; } return new Resource(parameters); } - _migrateResource(resource) { + _migrateResource(resource: LegacyResource | Resource) { // This function only returns a promise if a migration is necessary. // Since this is rarely the case, we therefore reduce the amount of // created Promises by making this differentiation // Check if its a fs/Resource v3, function 'hasProject' was // introduced with v3 therefore take it as the indicator - if (resource.hasProject) { + if (isLegacyResource(resource)) { return resource; } return this._createFromLegacyResource(resource); } - async _createFromLegacyResource(resource) { + async _createFromLegacyResource(resource: LegacyResource) { const options = { path: resource._path, statInfo: resource._statInfo, source: resource._source, - }; + } as Resource_Options; if (resource._stream) { options.buffer = await resource._getBufferFromStream(); @@ -235,14 +244,14 @@ class AbstractAdapter extends AbstractReaderWriter { return new Resource(options); } - _assignProjectToResource(resource) { + _assignProjectToResource(resource: Resource) { if (this._project) { // Assign project to resource if necessary if (resource.hasProject()) { if (resource.getProject() !== this._project) { throw new Error( `Unable to write resource associated with project ` + - `${resource.getProject().getName()} into adapter of project ${this._project.getName()}: ` + + `${resource.getProject()?.getName()} into adapter of project ${this._project.getName()}: ` + resource.getPath()); } return; @@ -252,7 +261,7 @@ class AbstractAdapter extends AbstractReaderWriter { } } - _resolveVirtualPathToBase(inputVirPath, writeMode = false) { + _resolveVirtualPathToBase(inputVirPath: string, writeMode = false) { if (!path.isAbsolute(inputVirPath)) { throw new Error(`Failed to resolve virtual path '${inputVirPath}': Path must be absolute`); } diff --git a/src/utils/mock-projects.d.ts b/src/utils/mock-projects.d.ts index e1fe7736..dadd8ade 100644 --- a/src/utils/mock-projects.d.ts +++ b/src/utils/mock-projects.d.ts @@ -11,6 +11,7 @@ declare module "@ui5/project/specifications/Project" { declare module "@ui5/logger" { interface logger { silly(x: string): void; + verbose(x: string): void; isLevelEnabled(x: string): boolean; } diff --git a/src/utils/tsUtils.ts b/src/utils/tsUtils.ts index 421cbded..32e65f25 100644 --- a/src/utils/tsUtils.ts +++ b/src/utils/tsUtils.ts @@ -1,3 +1,11 @@ +import Resource from "../Resource.js"; + export function isString(testString: unknown): testString is string { return testString instanceof String; } + +export function isLegacyResource(resource: unknown): resource is Resource { + // Check if its a fs/Resource v3, function 'hasProject' was + // introduced with v3 therefore take it as the indicator + return !!resource && !Object.hasOwnProperty.call(resource, "hasProject"); +} From 509fbd5cd5aa7638b268c936fb6fde81bb89dc7c Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Mon, 26 Aug 2024 13:19:50 +0300 Subject: [PATCH 14/69] refactor: Migrate FileSystem.js --- package.json | 1 + src/AbstractReader.ts | 4 +-- src/Resource.ts | 8 ++++-- src/adapters/FileSystem.ts | 54 +++++++++++++++++++++++------------- src/utils/mock-projects.d.ts | 1 + 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 95c7d87b..5903590a 100644 --- a/package.json +++ b/package.json @@ -128,6 +128,7 @@ "@istanbuljs/esm-loader-hook": "^0.2.0", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@stylistic/eslint-plugin": "^2.6.4", + "@types/graceful-fs": "^4.1.9", "@types/micromatch": "^4.0.9", "@types/node": "^20.11.0", "@types/pretty-hrtime": "^1.0.3", diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index 57f33efe..6ceecb4b 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -113,7 +113,7 @@ class AbstractReader { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - _runGlob(_pattern: string | string[], _options: object, _trace: Trace): Promise { + _runGlob(_pattern: string | string[], _options: {nodir: boolean}, _trace: Trace): Promise { throw new Error("Function '_runGlob' is not implemented"); } @@ -127,7 +127,7 @@ class AbstractReader { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - _byPath(_virPath: string, _options: object, _trace: Trace): Promise { + _byPath(_virPath: string, _options: object, _trace: Trace): Promise { throw new Error("Function '_byPath' is not implemented"); } } diff --git a/src/Resource.ts b/src/Resource.ts index 3ebcc3ab..b765517b 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -24,7 +24,11 @@ enum ALLOWED_SOURCE_METADATA_KEYS { */ type Resource_CreateReadableStream = () => stream.Readable; -type Resource_sourceMetadata = Partial>; +interface Resource_sourceMetadata { + [ALLOWED_SOURCE_METADATA_KEYS.ADAPTER]?: string; + [ALLOWED_SOURCE_METADATA_KEYS.FS_PATH]?: string; + [ALLOWED_SOURCE_METADATA_KEYS.CONTENT_MODIFIED]?: boolean; +}; // TODO: Validate these options. // Some might be required while others can be optional. @@ -128,7 +132,7 @@ class Resource { this.setPath(path); - this.#sourceMetadata = sourceMetadata || {}; + this.#sourceMetadata = sourceMetadata ?? {}; // This flag indicates whether a resource has changed from its original source. // resource.isModified() is not sufficient, since it only reflects the modification state of the diff --git a/src/adapters/FileSystem.ts b/src/adapters/FileSystem.ts index ff99873d..3b5ff2fa 100644 --- a/src/adapters/FileSystem.ts +++ b/src/adapters/FileSystem.ts @@ -2,14 +2,19 @@ import {getLogger} from "@ui5/logger"; const log = getLogger("resources:adapters:FileSystem"); import path from "node:path"; import {promisify} from "node:util"; -import fs from "graceful-fs"; +// import fs from "graceful-fs"; +// TODO: Migrate to "graceful-fs" +import fs from "node:fs"; const copyFile = promisify(fs.copyFile); const chmod = promisify(fs.chmod); const mkdir = promisify(fs.mkdir); const stat = promisify(fs.stat); -import {globby, isGitIgnored} from "globby"; +import {globby, GlobbyFilterFunction, isGitIgnored} from "globby"; import {PassThrough} from "node:stream"; import AbstractAdapter from "./AbstractAdapter.js"; +import type {Project} from "@ui5/project/specifications/Project"; +import Trace from "../tracing/Trace.js"; +import Resource, {LegacyResource, Resource_Options} from "../Resource.js"; const READ_ONLY_MODE = 0o444; const ADAPTER_NAME = "FileSystem"; @@ -22,6 +27,10 @@ const ADAPTER_NAME = "FileSystem"; * @extends @ui5/fs/adapters/AbstractAdapter */ class FileSystem extends AbstractAdapter { + _fsBasePath: string; + _useGitignore: boolean; + _isGitIgnored!: GlobbyFilterFunction; + /** * The Constructor. * @@ -35,7 +44,9 @@ class FileSystem extends AbstractAdapter { * Whether to apply any excludes defined in an optional .gitignore in the given fsBasePath directory * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) */ - constructor({virBasePath, project, fsBasePath, excludes, useGitignore = false}) { + constructor({virBasePath, project, fsBasePath, excludes, useGitignore = false}: + {virBasePath: string; project: Project; fsBasePath: string; excludes: string[]; useGitignore: boolean} + ) { super({virBasePath, project, excludes}); if (!fsBasePath) { @@ -58,7 +69,7 @@ class FileSystem extends AbstractAdapter { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - async _runGlob(patterns, options = {nodir: true}, trace) { + async _runGlob(patterns: string[], options = {nodir: true}, trace: Trace) { const opt = { cwd: this._fsBasePath, dot: true, @@ -68,7 +79,7 @@ class FileSystem extends AbstractAdapter { }; trace.globCall(); - const promises = []; + const promises: Promise[] = []; if (!opt.onlyFiles && patterns.includes("")) { // Match physical root directory promises.push(new Promise((resolve, reject) => { fs.stat(this._fsBasePath, (err, stat) => { @@ -112,7 +123,7 @@ class FileSystem extends AbstractAdapter { `the configured virtual base path of the adapter. Base path: '${this._virBasePath}'`); resolve(null); } - const fsPath = this._resolveToFileSystem(relPath); + const fsPath = this._resolveToFileSystem(relPath ?? ""); // Workaround for not getting the stat from the glob fs.stat(fsPath, (err, stat) => { @@ -139,7 +150,7 @@ class FileSystem extends AbstractAdapter { const results = await Promise.all(promises); // Flatten results - return Array.prototype.concat.apply([], results).filter(($) => $); + return Array.prototype.concat.apply([], results).filter(($) => $) as Resource[]; } /** @@ -151,7 +162,7 @@ class FileSystem extends AbstractAdapter { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource or null if not found */ - async _byPath(virPath, options, trace) { + async _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { const relPath = this._resolveVirtualPathToBase(virPath); if (relPath === null) { @@ -195,7 +206,7 @@ class FileSystem extends AbstractAdapter { if (options.nodir && statInfo.isDirectory()) { return null; } - const resourceOptions = { + const resourceOptions: Resource_Options = { project: this._project, statInfo, path: virPath, @@ -240,12 +251,15 @@ class FileSystem extends AbstractAdapter { * E.g. the final write of a resource after all processing is finished. * @returns {Promise} Promise resolving once data has been written */ - async _write(resource, {drain, readOnly}) { - resource = this._migrateResource(resource); - if (resource instanceof Promise) { + async _write(anyResource: LegacyResource | Resource, {drain, readOnly}: {drain: boolean; readOnly: boolean}) { + const potentialResourceP = this._migrateResource(anyResource); + let resource: Resource; + if (potentialResourceP instanceof Promise) { // Only await if the migrate function returned a promise // Otherwise await would automatically create a Promise, causing unwanted overhead - resource = await resource; + resource = await potentialResourceP; + } else { + resource = potentialResourceP; } this._assignProjectToResource(resource); if (drain && readOnly) { @@ -253,7 +267,7 @@ class FileSystem extends AbstractAdapter { "Do not use options 'drain' and 'readOnly' at the same time."); } - const relPath = this._resolveVirtualPathToBase(resource.getPath(), true); + const relPath = this._resolveVirtualPathToBase(resource.getPath(), true) ?? ""; const fsPath = this._resolveToFileSystem(relPath); const dirPath = path.dirname(fsPath); @@ -307,11 +321,11 @@ class FileSystem extends AbstractAdapter { } else { // Transform stream into buffer before writing contentStream = new PassThrough(); - const buffers = []; + const buffers: Buffer[] = []; contentStream.on("error", (err) => { reject(err); }); - contentStream.on("data", (data) => { + contentStream.on("data", (data: Buffer) => { buffers.push(data); }); contentStream.on("end", () => { @@ -321,7 +335,7 @@ class FileSystem extends AbstractAdapter { resource.getStream().pipe(contentStream); } - const writeOptions = {}; + const writeOptions: {mode?: number} = {}; if (readOnly) { writeOptions.mode = READ_ONLY_MODE; } @@ -330,8 +344,8 @@ class FileSystem extends AbstractAdapter { write.on("error", (err) => { reject(err); }); - write.on("close", (ex) => { - resolve(); + write.on("close", () => { + resolve(undefined); }); contentStream.pipe(write); }); @@ -353,7 +367,7 @@ class FileSystem extends AbstractAdapter { } } - _resolveToFileSystem(relPath) { + _resolveToFileSystem(relPath: string) { const fsPath = path.join(this._fsBasePath, relPath); if (!fsPath.startsWith(this._fsBasePath)) { diff --git a/src/utils/mock-projects.d.ts b/src/utils/mock-projects.d.ts index dadd8ade..7c72379e 100644 --- a/src/utils/mock-projects.d.ts +++ b/src/utils/mock-projects.d.ts @@ -5,6 +5,7 @@ declare module "@ui5/project/specifications/Project" { export interface Project { getName: () => string; + getType: () => "project" | "application" | "library"; } } From 2c63c10b8ec3bea45832182fb2dd6be444323dbb Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Mon, 26 Aug 2024 13:20:09 +0300 Subject: [PATCH 15/69] refactor: Resource --- src/Resource.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Resource.ts b/src/Resource.ts index b765517b..cd516f8c 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -80,7 +80,7 @@ class Resource { #name!: string; #path!: string; #sourceMetadata: Resource_sourceMetadata; - #statInfo: Stats; + #statInfo: Partial; #stream: stream.Readable | null | undefined; #streamDrained: boolean | undefined; #isModified: boolean; @@ -358,7 +358,7 @@ class Resource { * @returns {fs.Stats|object} Instance of [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} * or similar object */ - getStatInfo(): Stats { + getStatInfo(): Partial { return this.#statInfo; } From c00f93038fe3b726224cccf6cedb72bd96e67307 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Mon, 26 Aug 2024 14:51:31 +0300 Subject: [PATCH 16/69] fix: Provide graceful-fs definitions --- package.json | 1 - src/adapters/FileSystem.ts | 4 +--- src/utils/graceful-fs.d.ts | 6 ++++++ 3 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 src/utils/graceful-fs.d.ts diff --git a/package.json b/package.json index 5903590a..95c7d87b 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,6 @@ "@istanbuljs/esm-loader-hook": "^0.2.0", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@stylistic/eslint-plugin": "^2.6.4", - "@types/graceful-fs": "^4.1.9", "@types/micromatch": "^4.0.9", "@types/node": "^20.11.0", "@types/pretty-hrtime": "^1.0.3", diff --git a/src/adapters/FileSystem.ts b/src/adapters/FileSystem.ts index 3b5ff2fa..db5935f6 100644 --- a/src/adapters/FileSystem.ts +++ b/src/adapters/FileSystem.ts @@ -2,9 +2,7 @@ import {getLogger} from "@ui5/logger"; const log = getLogger("resources:adapters:FileSystem"); import path from "node:path"; import {promisify} from "node:util"; -// import fs from "graceful-fs"; -// TODO: Migrate to "graceful-fs" -import fs from "node:fs"; +import fs from "graceful-fs"; const copyFile = promisify(fs.copyFile); const chmod = promisify(fs.chmod); const mkdir = promisify(fs.mkdir); diff --git a/src/utils/graceful-fs.d.ts b/src/utils/graceful-fs.d.ts new file mode 100644 index 00000000..ca3301bf --- /dev/null +++ b/src/utils/graceful-fs.d.ts @@ -0,0 +1,6 @@ +// "graceful-fs" definitions just inherit the ones from node:fs, but are quite +// inconvenient. So, proxying the ones from node:fs would be better. +declare module "graceful-fs" { + import * as fs from "node:fs"; + export default fs; +} From 412af82f3663570aba4c3b3bc1d6ba3b13a525f0 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Mon, 26 Aug 2024 15:19:58 +0300 Subject: [PATCH 17/69] refactor: Migrate Memory.ts --- src/adapters/AbstractAdapter.ts | 2 +- src/adapters/Memory.ts | 39 ++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/adapters/AbstractAdapter.ts b/src/adapters/AbstractAdapter.ts index 506ce3b8..9ae596bd 100644 --- a/src/adapters/AbstractAdapter.ts +++ b/src/adapters/AbstractAdapter.ts @@ -261,7 +261,7 @@ class AbstractAdapter extends AbstractReaderWriter { } } - _resolveVirtualPathToBase(inputVirPath: string, writeMode = false) { + _resolveVirtualPathToBase(inputVirPath: string, writeMode = false): string { if (!path.isAbsolute(inputVirPath)) { throw new Error(`Failed to resolve virtual path '${inputVirPath}': Path must be absolute`); } diff --git a/src/adapters/Memory.ts b/src/adapters/Memory.ts index 7711b2c4..1653c034 100644 --- a/src/adapters/Memory.ts +++ b/src/adapters/Memory.ts @@ -2,6 +2,9 @@ import {getLogger} from "@ui5/logger"; const log = getLogger("resources:adapters:Memory"); import micromatch from "micromatch"; import AbstractAdapter from "./AbstractAdapter.js"; +import {Project} from "@ui5/project/specifications/Project"; +import Resource, {LegacyResource} from "../Resource.js"; +import Trace from "../tracing/Trace.js"; const ADAPTER_NAME = "Memory"; @@ -14,6 +17,9 @@ const ADAPTER_NAME = "Memory"; * @extends @ui5/fs/adapters/AbstractAdapter */ class Memory extends AbstractAdapter { + _virFiles: Record; + _virDirs: Record; + /** * The constructor. * @@ -24,10 +30,10 @@ class Memory extends AbstractAdapter { * @param {string[]} [parameters.excludes] List of glob patterns to exclude * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) */ - constructor({virBasePath, project, excludes}) { + constructor({virBasePath, project, excludes}: {virBasePath: string; project: Project; excludes: string[]}) { super({virBasePath, project, excludes}); - this._virFiles = Object.create(null); // map full of files - this._virDirs = Object.create(null); // map full of directories + this._virFiles = Object.create(null) as Record; // map full of files + this._virDirs = Object.create(null) as Record; // map full of directories } /** @@ -38,20 +44,20 @@ class Memory extends AbstractAdapter { * @param {object} resourceMap * @returns {Promise} */ - async _matchPatterns(patterns, resourceMap) { + async _matchPatterns(patterns: string[], resourceMap: Record): Promise { const resourcePaths = Object.keys(resourceMap); const matchedPaths = micromatch(resourcePaths, patterns, { dot: true, }); return await Promise.all(matchedPaths.map((virPath) => { - const resource = resourceMap[virPath]; + const resource: Resource = resourceMap[virPath]; if (resource) { return this._cloneResource(resource); } - })); + }).filter(($) => !!$)); } - async _cloneResource(resource) { + async _cloneResource(resource: Resource): Promise { const clonedResource = await resource.clone(); if (this._project) { clonedResource.setProject(this._project); @@ -69,7 +75,7 @@ class Memory extends AbstractAdapter { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - async _runGlob(patterns, options = {nodir: true}, trace) { + async _runGlob(patterns: string[], options = {nodir: true}, _trace: Trace) { if (patterns[0] === "" && !options.nodir) { // Match virtual root directory return [ this._createResource({ @@ -106,7 +112,7 @@ class Memory extends AbstractAdapter { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - async _byPath(virPath, options, trace) { + async _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { const relPath = this._resolveVirtualPathToBase(virPath); if (relPath === null) { return null; @@ -114,9 +120,9 @@ class Memory extends AbstractAdapter { trace.pathCall(); - const resource = this._virFiles[relPath]; + const resource: Resource = this._virFiles[relPath]; - if (!resource || (options.nodir && resource.getStatInfo().isDirectory())) { + if (!resource || (options.nodir && resource.getStatInfo().isDirectory?.())) { return null; } else { return await this._cloneResource(resource); @@ -130,12 +136,15 @@ class Memory extends AbstractAdapter { * @param {@ui5/fs/Resource} resource The Resource to write * @returns {Promise} Promise resolving once data has been written */ - async _write(resource) { - resource = this._migrateResource(resource); - if (resource instanceof Promise) { + async _write(anyResource: Resource | LegacyResource) { + const migratedResource = this._migrateResource(anyResource); + let resource: Resource; + if (migratedResource instanceof Promise) { // Only await if the migrate function returned a promise // Otherwise await would automatically create a Promise, causing unwanted overhead - resource = await resource; + resource = await migratedResource; + } else { + resource = migratedResource; } this._assignProjectToResource(resource); const relPath = this._resolveVirtualPathToBase(resource.getPath(), true); From 92f2f5c26af2abba477607dbd7790323894f2567 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Mon, 26 Aug 2024 15:40:50 +0300 Subject: [PATCH 18/69] refactor: Migrate collections --- src/AbstractReader.ts | 2 +- src/DuplexCollection.ts | 15 ++++++++--- src/ReaderCollectionPrioritized.ts | 40 ++++++++++++++++++------------ 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index 6ceecb4b..dd84624b 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -97,7 +97,7 @@ class AbstractReader { */ _byGlob(_virPattern: string | string[], _options: { - nodir: boolean + nodir: boolean; }, _trace: Trace): Promise { throw new Error("Function '_byGlob' is not implemented"); diff --git a/src/DuplexCollection.ts b/src/DuplexCollection.ts index df2b2672..6a91d11e 100644 --- a/src/DuplexCollection.ts +++ b/src/DuplexCollection.ts @@ -1,5 +1,8 @@ +import AbstractReader from "./AbstractReader.js"; import AbstractReaderWriter from "./AbstractReaderWriter.js"; import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; +import Resource from "./Resource.js"; +import Trace from "./tracing/Trace.js"; /** * Wrapper to keep readers and writers together @@ -10,6 +13,10 @@ import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; * @extends @ui5/fs/AbstractReaderWriter */ class DuplexCollection extends AbstractReaderWriter { + _reader: AbstractReader; + _writer: AbstractReaderWriter; + _combo: ReaderCollectionPrioritized; + /** * The Constructor. * @@ -19,7 +26,7 @@ class DuplexCollection extends AbstractReaderWriter { * A ReaderWriter instance which is only used for writing files * @param {string} [parameters.name=""] The collection name */ - constructor({reader, writer, name = ""}) { + constructor({reader, writer, name = ""}: {reader: AbstractReader; writer: AbstractReaderWriter; name: string}) { super(name); if (!reader) { @@ -51,7 +58,7 @@ class DuplexCollection extends AbstractReaderWriter { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving with a list of resources */ - _byGlob(virPattern, options, trace) { + _byGlob(virPattern: string | string[], options: {nodir: boolean}, trace: Trace) { return this._combo._byGlob(virPattern, options, trace); } @@ -65,7 +72,7 @@ class DuplexCollection extends AbstractReaderWriter { * @returns {Promise<@ui5/fs/Resource|null>} * Promise resolving to a single resource or null if no resource is found */ - _byPath(virPath, options, trace) { + _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { return this._combo._byPath(virPath, options, trace); } @@ -76,7 +83,7 @@ class DuplexCollection extends AbstractReaderWriter { * @param {@ui5/fs/Resource} resource The Resource to write * @returns {Promise} Promise resolving once data has been written */ - _write(resource) { + _write(resource: Resource) { return this._writer.write(resource); } } diff --git a/src/ReaderCollectionPrioritized.ts b/src/ReaderCollectionPrioritized.ts index 17a35abe..50ba9f8c 100644 --- a/src/ReaderCollectionPrioritized.ts +++ b/src/ReaderCollectionPrioritized.ts @@ -1,4 +1,6 @@ import AbstractReader from "./AbstractReader.js"; +import Resource from "./Resource.js"; +import Trace from "./tracing/Trace.js"; /** * Prioritized Resource Locator Collection @@ -9,6 +11,8 @@ import AbstractReader from "./AbstractReader.js"; * @extends @ui5/fs/AbstractReader */ class ReaderCollectionPrioritized extends AbstractReader { + _readers: AbstractReader[]; + /** * The constructor. * @@ -18,7 +22,7 @@ class ReaderCollectionPrioritized extends AbstractReader { * Prioritized list of resource readers (tried in the order provided). * If none are provided, the collection will never return any results. */ - constructor({readers, name}) { + constructor({readers, name}: {readers: AbstractReader[]; name: string}) { super(name); // Remove any undefined (empty) readers from array @@ -35,14 +39,16 @@ class ReaderCollectionPrioritized extends AbstractReader { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - _byGlob(pattern, options, trace) { + _byGlob(pattern: string | string[], options: {nodir: boolean}, trace: Trace) { return Promise.all(this._readers.map(function (resourceLocator) { return resourceLocator._byGlob(pattern, options, trace); })).then((result) => { - const files = Object.create(null); + const files = Object.create(null) as Record; const resources = []; // Prefer files found in preceding resource locators + // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < result.length; i++) { + // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let j = 0; j < result[i].length; j++) { const resource = result[i][j]; const path = resource.getPath(); @@ -53,7 +59,7 @@ class ReaderCollectionPrioritized extends AbstractReader { } } - trace.collection(this._name); + trace.collection(this._name!); return resources; }); } @@ -68,21 +74,23 @@ class ReaderCollectionPrioritized extends AbstractReader { * @returns {Promise<@ui5/fs/Resource|null>} * Promise resolving to a single resource or null if no resource is found */ - _byPath(virPath, options, trace) { - const that = this; - const byPath = (i) => { + _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { + // const that = this; + const byPath = (i: number) => { if (i > this._readers.length - 1) { - return null; + return Promise.resolve(null); } - return this._readers[i]._byPath(virPath, options, trace).then((resource) => { - if (resource) { - resource.pushCollection(that._name); - return resource; - } else { - return byPath(++i); - } - }); + return this._readers[i]._byPath(virPath, options, trace) + .then((resource: Resource | null): Resource | Promise => { + if (resource) { + resource.pushCollection(this._name!); + return resource; + } else { + return byPath(++i); + } + }); }; + return byPath(0); } } From 5bb2a976ebf51df4a9d98051c1779b0689561b5b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Mon, 26 Aug 2024 16:10:28 +0300 Subject: [PATCH 19/69] fix: Some cleanups --- package.json | 1 + src/utils/types/clone.d.ts | 3 +++ src/utils/{ => types}/graceful-fs.d.ts | 0 3 files changed, 4 insertions(+) create mode 100644 src/utils/types/clone.d.ts rename src/utils/{ => types}/graceful-fs.d.ts (100%) diff --git a/package.json b/package.json index 95c7d87b..fb1d629f 100644 --- a/package.json +++ b/package.json @@ -128,6 +128,7 @@ "@istanbuljs/esm-loader-hook": "^0.2.0", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@stylistic/eslint-plugin": "^2.6.4", + "@types/clone": "^2.1.4", "@types/micromatch": "^4.0.9", "@types/node": "^20.11.0", "@types/pretty-hrtime": "^1.0.3", diff --git a/src/utils/types/clone.d.ts b/src/utils/types/clone.d.ts new file mode 100644 index 00000000..c6862463 --- /dev/null +++ b/src/utils/types/clone.d.ts @@ -0,0 +1,3 @@ +declare module "clone" { + export default function clone(arg: T): T; +} diff --git a/src/utils/graceful-fs.d.ts b/src/utils/types/graceful-fs.d.ts similarity index 100% rename from src/utils/graceful-fs.d.ts rename to src/utils/types/graceful-fs.d.ts From 6320c4c8842252f09e577c22c872a7b282721f1b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 10:32:44 +0300 Subject: [PATCH 20/69] refactor: Migrate fsInterface --- src/AbstractReader.ts | 4 ++-- src/fsInterface.ts | 37 +++++++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index dd84624b..dde93eca 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -76,7 +76,7 @@ class AbstractReader { * @param {boolean} [options.nodir=true] Do not match directories * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - byPath(virPath: string, options = {nodir: true}): Promise { + byPath(virPath: string, options = {nodir: true}): Promise { const trace = new Trace(virPath); return this._byPath(virPath, options, trace).then(function (resource) { trace.printReport(); @@ -127,7 +127,7 @@ class AbstractReader { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - _byPath(_virPath: string, _options: object, _trace: Trace): Promise { + _byPath(_virPath: string, _options: object, _trace: Trace): Promise { throw new Error("Function '_byPath' is not implemented"); } } diff --git a/src/fsInterface.ts b/src/fsInterface.ts index fa814122..95aed004 100644 --- a/src/fsInterface.ts +++ b/src/fsInterface.ts @@ -1,11 +1,30 @@ -function toPosix(inputPath) { +import AbstractReader from "./AbstractReader.js"; +import type * as fs from "node:fs"; +import {Buffer} from "node:buffer"; + +function toPosix(inputPath: string) { return inputPath.replace(/\\/g, "/"); } +// Define the types for the options parameter +type Read_File_Options = {encoding?: string} | string | undefined; + +// Define the types for the callback functions +type Read_File_Callback = (err: Error | null, data?: Buffer | string) => void; +type Stat_Callback = (err: Error | null, stats?: fs.Stats) => void; +type Readdir_Callback = (err: Error | null, files?: string[]) => void; +type Mkdir_Callback = (err?: Error | null) => void; + /** * @public * @module @ui5/fs/fsInterface */ +interface File_System { + readFile: (fsPath: string, options: Read_File_Options, callback: Read_File_Callback) => void; + stat: (fsPath: string, callback: Stat_Callback) => void; + readdir: (fsPath: string, callback: Readdir_Callback) => void; + mkdir: (fsPath: string, callback: Mkdir_Callback) => void; +}; /** * Wraps readers to access them through a [Node.js fs]{@link https://nodejs.org/api/fs.html} styled interface. @@ -21,8 +40,8 @@ function toPosix(inputPath) { * [readdir]{@link https://nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback} and * [mkdir]{@link https://nodejs.org/api/fs.html#fs_fs_mkdir_path_options_callback} */ -function fsInterface(reader) { - return { +function fsInterface(reader: AbstractReader) { + const fileSystem: File_System = { readFile(fsPath, options, callback) { if (typeof options === "function") { callback = options; @@ -57,7 +76,7 @@ function fsInterface(reader) { }, stat(fsPath, callback) { const posixPath = toPosix(fsPath); - reader.byPath(posixPath, { + void reader.byPath(posixPath, { nodir: false, }).then(function (resource) { if (!resource) { @@ -65,17 +84,17 @@ function fsInterface(reader) { error.code = "ENOENT"; // "File or directory does not exist" callback(error); } else { - callback(null, resource.getStatInfo()); + callback(null, resource.getStatInfo() as fs.StatsBase); } }).catch(callback); }, readdir(fsPath, callback) { let posixPath = toPosix(fsPath); - if (!posixPath.match(/\/$/)) { + if (!(/\/$/.exec(posixPath))) { // Add trailing slash if not present posixPath += "/"; } - reader.byGlob(posixPath + "*", { + void reader.byGlob(posixPath + "*", { nodir: false, }).then((resources) => { const files = resources.map((resource) => { @@ -84,9 +103,11 @@ function fsInterface(reader) { callback(null, files); }).catch(callback); }, - mkdir(fsPath, callback) { + mkdir(_fsPath, callback) { setTimeout(callback, 0); }, }; + + return fileSystem; } export default fsInterface; From 37600e071e36f4b36f4278ee9223572d053ccb8c Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 10:40:10 +0300 Subject: [PATCH 21/69] refactor: Migrate ReaderCollection --- src/AbstractReader.ts | 4 ++-- src/ReaderCollection.ts | 26 ++++++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index dde93eca..e55d42df 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -76,7 +76,7 @@ class AbstractReader { * @param {boolean} [options.nodir=true] Do not match directories * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - byPath(virPath: string, options = {nodir: true}): Promise { + byPath(virPath: string, options = {nodir: true}): Promise { const trace = new Trace(virPath); return this._byPath(virPath, options, trace).then(function (resource) { trace.printReport(); @@ -127,7 +127,7 @@ class AbstractReader { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - _byPath(_virPath: string, _options: object, _trace: Trace): Promise { + _byPath(_virPath: string, _options: object, _trace: Trace): Promise { throw new Error("Function '_byPath' is not implemented"); } } diff --git a/src/ReaderCollection.ts b/src/ReaderCollection.ts index 47432871..521e80c9 100644 --- a/src/ReaderCollection.ts +++ b/src/ReaderCollection.ts @@ -1,4 +1,6 @@ import AbstractReader from "./AbstractReader.js"; +import Resource from "./Resource.js"; +import Trace from "./tracing/Trace.js"; /** * Resource Locator ReaderCollection @@ -9,6 +11,7 @@ import AbstractReader from "./AbstractReader.js"; * @extends @ui5/fs/AbstractReader */ class ReaderCollection extends AbstractReader { + _readers: AbstractReader[]; /** * The constructor. * @@ -18,7 +21,7 @@ class ReaderCollection extends AbstractReader { * List of resource readers (all tried in parallel). * If none are provided, the collection will never return any results. */ - constructor({name, readers}) { + constructor({name, readers}: {name: string; readers: AbstractReader[]}) { super(name); // Remove any undefined (empty) readers from array @@ -35,12 +38,12 @@ class ReaderCollection extends AbstractReader { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - _byGlob(pattern, options, trace) { + _byGlob(pattern: string[], options: {nodir: boolean}, trace: Trace) { return Promise.all(this._readers.map(function (resourceLocator) { return resourceLocator._byGlob(pattern, options, trace); })).then((result) => { - trace.collection(this._name); - return Array.prototype.concat.apply([], result); + trace.collection(this._name!); + return Array.prototype.concat.apply([], result) as Resource[]; // Flatten array }); } @@ -54,25 +57,24 @@ class ReaderCollection extends AbstractReader { * @returns {Promise<@ui5/fs/Resource|null>} * Promise resolving to a single resource or null if no resource is found */ - _byPath(virPath, options, trace) { - const that = this; + _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { const resourceLocatorCount = this._readers.length; let resolveCount = 0; if (resourceLocatorCount === 0) { // Short-circuit if there are no readers (Promise.race does not settle for empty arrays) - trace.collection(that._name); + trace.collection(this._name!); return Promise.resolve(null); } // Using Promise.race to deliver files that can be found as fast as possible - return Promise.race(this._readers.map(function (resourceLocator) { - return resourceLocator._byPath(virPath, options, trace).then(function (resource) { - return new Promise(function (resolve, reject) { - trace.collection(that._name); + return Promise.race(this._readers.map((resourceLocator) => { + return resourceLocator._byPath(virPath, options, trace).then((resource) => { + return new Promise((resolve) => { + trace.collection(this._name!); resolveCount++; if (resource) { - resource.pushCollection(that._name); + resource.pushCollection(this._name!); resolve(resource); } else if (resolveCount === resourceLocatorCount) { resolve(null); From e6a86dbf427301d276f9c7151427ff5e30701db7 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 10:59:29 +0300 Subject: [PATCH 22/69] refactor: Migrate ResourceFacade --- src/Resource.ts | 2 +- src/ResourceFacade.ts | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Resource.ts b/src/Resource.ts index cd516f8c..5c51149a 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -22,7 +22,7 @@ enum ALLOWED_SOURCE_METADATA_KEYS { * @callback @ui5/fs/Resource~createStream * @returns {stream.Readable} A readable stream of a resources content */ -type Resource_CreateReadableStream = () => stream.Readable; +export type Resource_CreateReadableStream = () => stream.Readable; interface Resource_sourceMetadata { [ALLOWED_SOURCE_METADATA_KEYS.ADAPTER]?: string; diff --git a/src/ResourceFacade.ts b/src/ResourceFacade.ts index 07a0b10e..d7f7eabc 100644 --- a/src/ResourceFacade.ts +++ b/src/ResourceFacade.ts @@ -1,4 +1,9 @@ import posixPath from "node:path/posix"; +import Resource from "./Resource.js"; +import {Buffer} from "node:buffer"; +import stream from "node:stream"; +import {Resource_CreateReadableStream} from "./Resource.js"; +import {Project} from "@ui5/project/specifications/Project"; /** * A {@link @ui5/fs/Resource Resource} with a different path than it's original @@ -19,7 +24,7 @@ class ResourceFacade { * @param {string} parameters.path Virtual path of the facade resource * @param {@ui5/fs/Resource} parameters.resource Resource to conceal */ - constructor({path, resource}) { + constructor({path, resource}: {path: string; resource: Resource}) { if (!path) { throw new Error("Unable to create ResourceFacade: Missing parameter 'path'"); } @@ -61,7 +66,7 @@ class ResourceFacade { * @public * @param {string} path (Virtual) path of the resource */ - setPath(path) { + setPath(_path: string) { throw new Error(`The path of a ResourceFacade can't be changed`); } @@ -100,7 +105,7 @@ class ResourceFacade { * @public * @param {Buffer} buffer Buffer instance */ - setBuffer(buffer) { + setBuffer(buffer: Buffer) { return this.#resource.setBuffer(buffer); } @@ -120,7 +125,7 @@ class ResourceFacade { * @public * @param {string} string Resource content */ - setString(string) { + setString(string: string) { return this.#resource.setString(string); } @@ -146,7 +151,7 @@ class ResourceFacade { * @param {stream.Readable|@ui5/fs/Resource~createStream} stream Readable stream of the resource content or callback for dynamic creation of a readable stream */ - setStream(stream) { + setStream(stream: stream.Readable | Resource_CreateReadableStream) { return this.#resource.setStream(stream); } @@ -179,7 +184,7 @@ class ResourceFacade { * * @param {string} name Resource collection name */ - pushCollection(name) { + pushCollection(name: string) { return this.#resource.pushCollection(name); } @@ -215,7 +220,7 @@ class ResourceFacade { * @public * @param {@ui5/project/specifications/Project} project Project this resource is associated with */ - setProject(project) { + setProject(project: Project) { return this.#resource.setProject(project); } From c8630a7689ff550340065a8dc12952bbbbe7a346 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 11:15:38 +0300 Subject: [PATCH 23/69] refactor: Migrate resourceFactory --- src/adapters/AbstractAdapter.ts | 6 +++--- src/adapters/Memory.ts | 2 +- src/resourceFactory.ts | 34 +++++++++++++++++++++------------ 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/adapters/AbstractAdapter.ts b/src/adapters/AbstractAdapter.ts index 9ae596bd..b694bc72 100644 --- a/src/adapters/AbstractAdapter.ts +++ b/src/adapters/AbstractAdapter.ts @@ -23,7 +23,7 @@ class AbstractAdapter extends AbstractReaderWriter { _virBaseDir: string; _excludes: string[]; _excludesNegated: string[]; - _project: Project; + _project?: Project; /** * The constructor @@ -36,7 +36,7 @@ class AbstractAdapter extends AbstractReaderWriter { * @param {object} [parameters.project] Experimental, internal parameter. Do not use */ constructor({virBasePath, excludes = [], project}: - {virBasePath: string; excludes: string[]; project: Project}) { + {virBasePath: string; excludes?: string[]; project?: Project}) { if (new.target === AbstractAdapter) { throw new TypeError("Class 'AbstractAdapter' is abstract"); } @@ -261,7 +261,7 @@ class AbstractAdapter extends AbstractReaderWriter { } } - _resolveVirtualPathToBase(inputVirPath: string, writeMode = false): string { + _resolveVirtualPathToBase(inputVirPath: string, writeMode = false): string | null { if (!path.isAbsolute(inputVirPath)) { throw new Error(`Failed to resolve virtual path '${inputVirPath}': Path must be absolute`); } diff --git a/src/adapters/Memory.ts b/src/adapters/Memory.ts index 1653c034..2caf6ea5 100644 --- a/src/adapters/Memory.ts +++ b/src/adapters/Memory.ts @@ -30,7 +30,7 @@ class Memory extends AbstractAdapter { * @param {string[]} [parameters.excludes] List of glob patterns to exclude * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) */ - constructor({virBasePath, project, excludes}: {virBasePath: string; project: Project; excludes: string[]}) { + constructor({virBasePath, project, excludes}: {virBasePath: string; project?: Project; excludes?: string[]}) { super({virBasePath, project, excludes}); this._virFiles = Object.create(null) as Record; // map full of files this._virDirs = Object.create(null) as Record; // map full of directories diff --git a/src/resourceFactory.ts b/src/resourceFactory.ts index 611e450a..f3690d9a 100644 --- a/src/resourceFactory.ts +++ b/src/resourceFactory.ts @@ -5,11 +5,14 @@ import FsAdapter from "./adapters/FileSystem.js"; import MemAdapter from "./adapters/Memory.js"; import ReaderCollection from "./ReaderCollection.js"; import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; -import Resource from "./Resource.js"; +import Resource, {Resource_Options} from "./Resource.js"; import WriterCollection from "./WriterCollection.js"; import Filter from "./readers/Filter.js"; import Link from "./readers/Link.js"; import {getLogger} from "@ui5/logger"; +import {Project} from "@ui5/project/specifications/Project"; +import AbstractReader from "./AbstractReader.js"; +import AbstractReaderWriter from "./AbstractReaderWriter.js"; const log = getLogger("resources:resourceFactory"); /** @@ -38,7 +41,9 @@ const log = getLogger("resources:resourceFactory"); * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) * @returns {@ui5/fs/adapters/FileSystem|@ui5/fs/adapters/Memory} File System- or Virtual Adapter */ -export function createAdapter({fsBasePath, virBasePath, project, excludes, useGitignore}) { +export function createAdapter({fsBasePath, virBasePath, project, excludes, useGitignore}: +{fsBasePath: string; virBasePath: string; project: Project; excludes: string[]; useGitignore: boolean} +) { if (fsBasePath) { return new FsAdapter({fsBasePath, virBasePath, project, excludes, useGitignore}); } else { @@ -59,7 +64,9 @@ export function createAdapter({fsBasePath, virBasePath, project, excludes, useGi * @param {string} [parameters.name] Name for the reader collection * @returns {@ui5/fs/ReaderCollection} Reader collection wrapping an adapter */ -export function createReader({fsBasePath, virBasePath, project, excludes = [], name}) { +export function createReader({fsBasePath, virBasePath, project, excludes = [], name}: +{fsBasePath: string; virBasePath: string; project: Project; excludes: string[]; name: string} +) { if (!fsBasePath) { // Creating a reader with a memory adapter seems pointless right now // since there would be no way to fill the adapter with resources @@ -73,7 +80,7 @@ export function createReader({fsBasePath, virBasePath, project, excludes = [], n // ui5 runtime path of the excluded resources. Therefore, only allow paths like /resources//test // starting with specVersion 4.0 if (excludes.length && project && project.getType() === "application") { - normalizedExcludes = excludes.map((pattern) => { + const nestedNormalizedExcludes = excludes.map((pattern) => { if (pattern.startsWith(virBasePath) || pattern.startsWith("!" + virBasePath)) { return pattern; } @@ -82,7 +89,7 @@ export function createReader({fsBasePath, virBasePath, project, excludes = [], n return prefixGlobPattern(pattern, virBasePath); }); // Flatten list of patterns - normalizedExcludes = Array.prototype.concat.apply([], normalizedExcludes); + normalizedExcludes = Array.prototype.concat.apply([], nestedNormalizedExcludes) as string[]; log.verbose(`Effective exclude patterns for application project ${project.getName()}:\n` + normalizedExcludes.join(", ")); } @@ -106,7 +113,7 @@ export function createReader({fsBasePath, virBasePath, project, excludes = [], n * @param {@ui5/fs/AbstractReader[]} parameters.readers List of resource readers (all tried in parallel) * @returns {@ui5/fs/ReaderCollection} Reader collection wrapping provided readers */ -export function createReaderCollection({name, readers}) { +export function createReaderCollection({name, readers}: {name: string; readers: AbstractReader[]}) { return new ReaderCollection({ name, readers, @@ -123,7 +130,7 @@ export function createReaderCollection({name, readers}) { * (first is tried first) * @returns {@ui5/fs/ReaderCollectionPrioritized} Reader collection wrapping provided readers */ -export function createReaderCollectionPrioritized({name, readers}) { +export function createReaderCollectionPrioritized({name, readers}: {name: string; readers: AbstractReader[]}) { return new ReaderCollectionPrioritized({ name, readers, @@ -140,7 +147,7 @@ export function createReaderCollectionPrioritized({name, readers}) { * paths to writers. Path are matched greedy * @returns {@ui5/fs/WriterCollection} Writer collection wrapping provided writers */ -export function createWriterCollection({name, writerMapping}) { +export function createWriterCollection({name, writerMapping}: {name: string; writerMapping: AbstractReaderWriter[]}) { return new WriterCollection({ name, writerMapping, @@ -155,7 +162,7 @@ export function createWriterCollection({name, writerMapping}) { * @param {object} parameters Parameters to be passed to the resource constructor * @returns {@ui5/fs/Resource} Resource */ -export function createResource(parameters) { +export function createResource(parameters: Resource_Options) { return new Resource(parameters); } @@ -175,7 +182,9 @@ export function createResource(parameters) { * @param {string} [parameters.virBasePath="/"] Virtual base path * @returns {@ui5/fs/DuplexCollection} DuplexCollection which wraps the provided resource locators */ -export function createWorkspace({reader, writer, virBasePath = "/", name = "workspace"}) { +export function createWorkspace({reader, writer, virBasePath = "/", name = "workspace"}: +{reader: AbstractReader; writer: AbstractReaderWriter; virBasePath: string; name: string} +) { if (!writer) { writer = new MemAdapter({ virBasePath, @@ -246,7 +255,7 @@ export function createLinkReader(parameters) { * @param {string} parameters.namespace Project namespace * @returns {@ui5/fs/readers/Link} Reader instance */ -export function createFlatReader({reader, namespace}) { +export function createFlatReader({reader, namespace}: {reader: AbstractReader; namespace: string}) { return new Link({ reader: reader, pathMapping: { @@ -264,10 +273,11 @@ export function createFlatReader({reader, namespace}) { * @param {string} virBaseDir virtual base directory path to prefix the given patterns with * @returns {string[]} A list of normalized glob patterns */ -export function prefixGlobPattern(virPattern, virBaseDir) { +export function prefixGlobPattern(virPattern: string, virBaseDir: string) { const mm = new minimatch.Minimatch(virPattern); const resultGlobs = []; + // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < mm.globSet.length; i++) { let resultPattern = path.posix.join(virBaseDir, mm.globSet[i]); From 67c63285926deb5e5a72e497cc69992cad95ab5b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 11:52:47 +0300 Subject: [PATCH 24/69] refactor: Migrate ResourceTagCollection --- src/ResourceTagCollection.ts | 48 +++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/ResourceTagCollection.ts b/src/ResourceTagCollection.ts index 9214c15b..48850b04 100644 --- a/src/ResourceTagCollection.ts +++ b/src/ResourceTagCollection.ts @@ -1,7 +1,15 @@ const tagNamespaceRegExp = /^[a-z][a-z0-9]+$/; // part before the colon const tagNameRegExp = /^[A-Z][A-Za-z0-9]+$/; // part after the colon +import Resource from "./Resource.js"; import ResourceFacade from "./ResourceFacade.js"; +interface PathTagsInterface { + [key: string]: string | number | boolean | undefined | PathTagsInterface; +}; +export function isPathTagsInterface(elem: unknown): elem is PathTagsInterface { + return typeof elem === "object"; +} + /** * A ResourceTagCollection * @@ -10,7 +18,13 @@ import ResourceFacade from "./ResourceFacade.js"; * @alias @ui5/fs/internal/ResourceTagCollection */ class ResourceTagCollection { - constructor({allowedTags = [], allowedNamespaces = [], tags}) { + _allowedTags: string[]; + _allowedNamespaces: string[]; + _pathTags: PathTagsInterface; + _allowedNamespacesRegExp: null | RegExp; + + constructor({allowedTags = [], allowedNamespaces = [], tags}: + {allowedTags: string[]; allowedNamespaces: string[]; tags: PathTagsInterface}) { this._allowedTags = allowedTags; // Allowed tags are validated during use this._allowedNamespaces = allowedNamespaces; @@ -32,32 +46,38 @@ class ResourceTagCollection { this._pathTags = tags || Object.create(null); } - setTag(resourcePath, tag, value = true) { + setTag(resourcePath: string, tag: string, value: string | number | boolean = true) { resourcePath = this._getPath(resourcePath); this._validateTag(tag); this._validateValue(value); if (!this._pathTags[resourcePath]) { - this._pathTags[resourcePath] = Object.create(null); + this._pathTags[resourcePath] = Object.create(null) as PathTagsInterface; + } + + const pointer = this._pathTags[resourcePath]; + if (isPathTagsInterface(pointer)) { + pointer[tag] = value; } - this._pathTags[resourcePath][tag] = value; } - clearTag(resourcePath, tag) { + clearTag(resourcePath: string, tag: string) { resourcePath = this._getPath(resourcePath); this._validateTag(tag); - if (this._pathTags[resourcePath]) { - this._pathTags[resourcePath][tag] = undefined; + const pointer = this._pathTags[resourcePath]; + if (isPathTagsInterface(pointer)) { + pointer[tag] = undefined; } } - getTag(resourcePath, tag) { + getTag(resourcePath: string, tag: string): string | number | boolean | undefined | PathTagsInterface { resourcePath = this._getPath(resourcePath); this._validateTag(tag); - if (this._pathTags[resourcePath]) { - return this._pathTags[resourcePath][tag]; + const pointer = this._pathTags[resourcePath]; + if (isPathTagsInterface(pointer)) { + return pointer[tag]; } } @@ -65,14 +85,14 @@ class ResourceTagCollection { return this._pathTags; } - acceptsTag(tag) { + acceptsTag(tag: string) { if (this._allowedTags.includes(tag) || this._allowedNamespacesRegExp?.test(tag)) { return true; } return false; } - _getPath(resourcePath) { + _getPath(resourcePath: ResourceFacade | Resource | string): string { if (typeof resourcePath !== "string") { if (resourcePath instanceof ResourceFacade) { resourcePath = resourcePath.getConcealedResource().getPath(); @@ -86,7 +106,7 @@ class ResourceTagCollection { return resourcePath; } - _validateTag(tag) { + _validateTag(tag: string) { if (!tag.includes(":")) { throw new Error(`Invalid Tag "${tag}": Colon required after namespace`); } @@ -112,7 +132,7 @@ class ResourceTagCollection { } } - _validateValue(value) { + _validateValue(value: string | number | boolean) { const type = typeof value; if (!["string", "number", "boolean"].includes(type)) { throw new Error( From 00ab25fd8e3bed624175dbd44fe91b9efda2dad4 Mon Sep 17 00:00:00 2001 From: Max Reichmann Date: Tue, 27 Aug 2024 11:18:46 +0200 Subject: [PATCH 25/69] refactor(Filter.ts): Add datatypes to arguments/properties --- src/readers/Filter.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/readers/Filter.ts b/src/readers/Filter.ts index b95654da..26822267 100644 --- a/src/readers/Filter.ts +++ b/src/readers/Filter.ts @@ -1,4 +1,6 @@ import AbstractReader from "../AbstractReader.js"; +import Resource from "../Resource.js"; +import Trace from "../tracing/Trace.js"; /** * A reader that allows dynamic filtering of resources passed through it @@ -9,6 +11,9 @@ import AbstractReader from "../AbstractReader.js"; * @extends @ui5/fs/AbstractReader */ class Filter extends AbstractReader { + _reader: AbstractReader; + _callback: (resource: Resource) => boolean; + /** * Filter callback * @@ -21,13 +26,13 @@ class Filter extends AbstractReader { /** * Constructor * - * @public + * @public * @param {object} parameters Parameters * @param {@ui5/fs/AbstractReader} parameters.reader The resource reader or collection to wrap * @param {@ui5/fs/readers/Filter~callback} parameters.callback * Filter function. Will be called for every resource read through this reader. */ - constructor({reader, callback}) { + constructor({reader, callback}: {reader: AbstractReader; callback: (resource: Resource) => boolean}) { super(); if (!reader) { throw new Error(`Missing parameter "reader"`); @@ -49,7 +54,7 @@ class Filter extends AbstractReader { * @param {@ui5/fs/tracing/Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - async _byGlob(pattern, options, trace) { + async _byGlob(pattern: string | string[], options: {nodir: boolean}, trace: Trace) { const result = await this._reader._byGlob(pattern, options, trace); return result.filter(this._callback); } @@ -63,7 +68,7 @@ class Filter extends AbstractReader { * @param {@ui5/fs/tracing/Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - async _byPath(virPath, options, trace) { + async _byPath(virPath: string, options: {nodir: boolean}, trace: Trace): Promise { const result = await this._reader._byPath(virPath, options, trace); if (result && !this._callback(result)) { return null; From fb7dfab59bab07b3785de0d44648f8ada98568d4 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 12:23:16 +0300 Subject: [PATCH 26/69] refactor: WriterCollection --- src/ReaderCollection.ts | 2 +- src/WriterCollection.ts | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ReaderCollection.ts b/src/ReaderCollection.ts index 521e80c9..57a104a4 100644 --- a/src/ReaderCollection.ts +++ b/src/ReaderCollection.ts @@ -38,7 +38,7 @@ class ReaderCollection extends AbstractReader { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - _byGlob(pattern: string[], options: {nodir: boolean}, trace: Trace) { + _byGlob(pattern: string | string[], options: {nodir: boolean}, trace: Trace) { return Promise.all(this._readers.map(function (resourceLocator) { return resourceLocator._byGlob(pattern, options, trace); })).then((result) => { diff --git a/src/WriterCollection.ts b/src/WriterCollection.ts index cbcbc727..f6043410 100644 --- a/src/WriterCollection.ts +++ b/src/WriterCollection.ts @@ -1,6 +1,8 @@ import AbstractReaderWriter from "./AbstractReaderWriter.js"; import ReaderCollection from "./ReaderCollection.js"; import escapeStringRegExp from "escape-string-regexp"; +import Trace from "./tracing/Trace.js"; +import Resource from "./Resource.js"; /** * Resource Locator WriterCollection @@ -11,6 +13,10 @@ import escapeStringRegExp from "escape-string-regexp"; * @extends @ui5/fs/AbstractReaderWriter */ class WriterCollection extends AbstractReaderWriter { + _basePathRegex: string; + _writerMapping: Record; + _readerCollection: ReaderCollection; + /** * The constructor. * @@ -28,7 +34,7 @@ class WriterCollection extends AbstractReaderWriter { * } * }); */ - constructor({name, writerMapping}) { + constructor({name, writerMapping}: {name: string; writerMapping: Record}) { super(name); if (!writerMapping) { @@ -41,7 +47,7 @@ class WriterCollection extends AbstractReaderWriter { // Create a regular expression (which is greedy by nature) from all paths to easily // find the correct writer for any given resource path - this._basePathRegex = basePaths.sort().reduce((regex, basePath, idx) => { + this._basePathRegex = basePaths.sort().reduce((regex, basePath) => { // Validate base path if (!basePath) { throw new Error(`Empty path in path mapping of WriterCollection ${this._name}`); @@ -75,7 +81,7 @@ class WriterCollection extends AbstractReaderWriter { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - _byGlob(pattern, options, trace) { + _byGlob(pattern: string | string[], options: {nodir: boolean}, trace: Trace) { return this._readerCollection._byGlob(pattern, options, trace); } @@ -88,7 +94,7 @@ class WriterCollection extends AbstractReaderWriter { * @param {@ui5/fs/tracing.Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - _byPath(virPath, options, trace) { + _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { return this._readerCollection._byPath(virPath, options, trace); } @@ -100,7 +106,7 @@ class WriterCollection extends AbstractReaderWriter { * @param {object} [options] Write options, see above * @returns {Promise} Promise resolving once data has been written */ - _write(resource, options) { + _write(resource: Resource, options: object) { const resourcePath = resource.getPath(); const basePathMatch = resourcePath.match(this._basePathRegex); From e507ae4d357930156fb178b707a15ca5c9eec737 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 12:27:56 +0300 Subject: [PATCH 27/69] fix: resourceFactory filter params type --- src/readers/Filter.ts | 7 ++++++- src/resourceFactory.ts | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/readers/Filter.ts b/src/readers/Filter.ts index 26822267..426d18a0 100644 --- a/src/readers/Filter.ts +++ b/src/readers/Filter.ts @@ -2,6 +2,11 @@ import AbstractReader from "../AbstractReader.js"; import Resource from "../Resource.js"; import Trace from "../tracing/Trace.js"; +export interface Filter_Params { + reader: AbstractReader; + callback: (resource: Resource) => boolean; +}; + /** * A reader that allows dynamic filtering of resources passed through it * @@ -32,7 +37,7 @@ class Filter extends AbstractReader { * @param {@ui5/fs/readers/Filter~callback} parameters.callback * Filter function. Will be called for every resource read through this reader. */ - constructor({reader, callback}: {reader: AbstractReader; callback: (resource: Resource) => boolean}) { + constructor({reader, callback}: Filter_Params) { super(); if (!reader) { throw new Error(`Missing parameter "reader"`); diff --git a/src/resourceFactory.ts b/src/resourceFactory.ts index f3690d9a..f0eead34 100644 --- a/src/resourceFactory.ts +++ b/src/resourceFactory.ts @@ -7,7 +7,7 @@ import ReaderCollection from "./ReaderCollection.js"; import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; import Resource, {Resource_Options} from "./Resource.js"; import WriterCollection from "./WriterCollection.js"; -import Filter from "./readers/Filter.js"; +import Filter, {Filter_Params} from "./readers/Filter.js"; import Link from "./readers/Link.js"; import {getLogger} from "@ui5/logger"; import {Project} from "@ui5/project/specifications/Project"; @@ -210,7 +210,7 @@ export function createWorkspace({reader, writer, virBasePath = "/", name = "work * Filter function. Will be called for every resource passed through this reader. * @returns {@ui5/fs/readers/Filter} Reader instance */ -export function createFilterReader(parameters) { +export function createFilterReader(parameters: Filter_Params) { return new Filter(parameters); } From 882dfcd1566a8a700fb2282aa23595240ec47c9a Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 13:23:57 +0300 Subject: [PATCH 28/69] fix: Tests --- test/lib/adapters/Memory_read.ts | 1 + test/lib/fsInterface.ts | 2 +- test/lib/glob.ts | 1 + test/lib/resources.ts | 2 +- test/lib/tracing/traceSummary.ts | 2 +- 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test/lib/adapters/Memory_read.ts b/test/lib/adapters/Memory_read.ts index eda4e482..735fa206 100644 --- a/test/lib/adapters/Memory_read.ts +++ b/test/lib/adapters/Memory_read.ts @@ -20,6 +20,7 @@ function matchGlobResult(t, resources, expectedResources) { return resource.getPath(); }); + // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < expectedResources.length; i++) { const expectedResource = expectedResources[i]; t.true( diff --git a/test/lib/fsInterface.ts b/test/lib/fsInterface.ts index 34cd2e4a..c0f7df9c 100644 --- a/test/lib/fsInterface.ts +++ b/test/lib/fsInterface.ts @@ -49,7 +49,7 @@ test("MemAdapter: readFile", async (t) => { path: "/foo.txt", string: `content of ${fsPath}`, })); - `content of ${fsPath}`; + // `content of ${fsPath}`; await assertReadFile(t, readFile, "", fsPath); }); diff --git a/test/lib/glob.ts b/test/lib/glob.ts index 11273f6f..6e84564f 100644 --- a/test/lib/glob.ts +++ b/test/lib/glob.ts @@ -18,6 +18,7 @@ function matchGlobResult(t, resources, expectedResources) { return resource.getPath(); }); + // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < expectedResources.length; i++) { const expectedResource = expectedResources[i]; t.true( diff --git a/test/lib/resources.ts b/test/lib/resources.ts index 2bd3f1c8..4674ae23 100644 --- a/test/lib/resources.ts +++ b/test/lib/resources.ts @@ -5,7 +5,7 @@ import {readFile} from "node:fs/promises"; import {createAdapter, createFilterReader, createFlatReader, createLinkReader, createResource} from "../../lib/resourceFactory.js"; -test.afterEach.always((t) => { +test.afterEach.always((_t) => { sinon.restore(); }); diff --git a/test/lib/tracing/traceSummary.ts b/test/lib/tracing/traceSummary.ts index 9dda79d3..3d2de477 100644 --- a/test/lib/tracing/traceSummary.ts +++ b/test/lib/tracing/traceSummary.ts @@ -17,7 +17,7 @@ async function createMock(t, isLevelEnabled = true) { return t.context; } -test.afterEach.always((t) => { +test.afterEach.always((_t) => { sinon.restore(); }); From 77963668ae7997ae9d5bfd691c9487f676f7542c Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 13:34:19 +0300 Subject: [PATCH 29/69] refactor: Clear build files --- lib/AbstractReader.js | 122 ------- lib/AbstractReader.js.map | 1 - lib/AbstractReaderWriter.js | 67 ---- lib/AbstractReaderWriter.js.map | 1 - lib/DuplexCollection.js | 77 ---- lib/DuplexCollection.js.map | 1 - lib/ReaderCollection.js | 81 ----- lib/ReaderCollection.js.map | 1 - lib/ReaderCollectionPrioritized.js | 86 ----- lib/ReaderCollectionPrioritized.js.map | 1 - lib/Resource.js | 463 ------------------------- lib/Resource.js.map | 1 - lib/ResourceFacade.js | 240 ------------- lib/ResourceFacade.js.map | 1 - lib/ResourceTagCollection.js | 107 ------ lib/ResourceTagCollection.js.map | 1 - lib/WriterCollection.js | 105 ------ lib/WriterCollection.js.map | 1 - lib/adapters/AbstractAdapter.js | 280 --------------- lib/adapters/AbstractAdapter.js.map | 1 - lib/adapters/FileSystem.js | 345 ------------------ lib/adapters/FileSystem.js.map | 1 - lib/adapters/Memory.js | 162 --------- lib/adapters/Memory.js.map | 1 - lib/fsInterface.js | 90 ----- lib/fsInterface.js.map | 1 - lib/readers/Filter.js | 71 ---- lib/readers/Filter.js.map | 1 - lib/readers/Link.js | 131 ------- lib/readers/Link.js.map | 1 - lib/resourceFactory.js | 266 -------------- lib/resourceFactory.js.map | 1 - lib/tracing/Trace.js | 91 ----- lib/tracing/Trace.js.map | 1 - lib/tracing/traceSummary.js | 113 ------ lib/tracing/traceSummary.js.map | 1 - 36 files changed, 2915 deletions(-) delete mode 100644 lib/AbstractReader.js delete mode 100644 lib/AbstractReader.js.map delete mode 100644 lib/AbstractReaderWriter.js delete mode 100644 lib/AbstractReaderWriter.js.map delete mode 100644 lib/DuplexCollection.js delete mode 100644 lib/DuplexCollection.js.map delete mode 100644 lib/ReaderCollection.js delete mode 100644 lib/ReaderCollection.js.map delete mode 100644 lib/ReaderCollectionPrioritized.js delete mode 100644 lib/ReaderCollectionPrioritized.js.map delete mode 100644 lib/Resource.js delete mode 100644 lib/Resource.js.map delete mode 100644 lib/ResourceFacade.js delete mode 100644 lib/ResourceFacade.js.map delete mode 100644 lib/ResourceTagCollection.js delete mode 100644 lib/ResourceTagCollection.js.map delete mode 100644 lib/WriterCollection.js delete mode 100644 lib/WriterCollection.js.map delete mode 100644 lib/adapters/AbstractAdapter.js delete mode 100644 lib/adapters/AbstractAdapter.js.map delete mode 100644 lib/adapters/FileSystem.js delete mode 100644 lib/adapters/FileSystem.js.map delete mode 100644 lib/adapters/Memory.js delete mode 100644 lib/adapters/Memory.js.map delete mode 100644 lib/fsInterface.js delete mode 100644 lib/fsInterface.js.map delete mode 100644 lib/readers/Filter.js delete mode 100644 lib/readers/Filter.js.map delete mode 100644 lib/readers/Link.js delete mode 100644 lib/readers/Link.js.map delete mode 100644 lib/resourceFactory.js delete mode 100644 lib/resourceFactory.js.map delete mode 100644 lib/tracing/Trace.js delete mode 100644 lib/tracing/Trace.js.map delete mode 100644 lib/tracing/traceSummary.js delete mode 100644 lib/tracing/traceSummary.js.map diff --git a/lib/AbstractReader.js b/lib/AbstractReader.js deleted file mode 100644 index e941c375..00000000 --- a/lib/AbstractReader.js +++ /dev/null @@ -1,122 +0,0 @@ -import randomInt from "random-int"; -import Trace from "./tracing/Trace.js"; -/** - * Abstract resource locator implementing the general API for reading resources - * - * @abstract - * @public - * @class - * @alias @ui5/fs/AbstractReader - */ -class AbstractReader { - /** - * The constructor. - * - * @public - * @param {string} name Name of the reader. Typically used for tracing purposes - */ - constructor(name) { - if (new.target === AbstractReader) { - throw new TypeError("Class 'AbstractReader' is abstract"); - } - this._name = name; - } - /* - * Returns the name of the reader instance. This can be used for logging/tracing purposes. - * - * @returns {string} Name of the reader - */ - getName() { - return this._name || ``; - } - /** - * Locates resources by matching glob patterns. - * - * @example - * byGlob("**‏/*.{html,htm}"); - * byGlob("**‏/.library"); - * byGlob("/pony/*"); - * - * @public - * @param {string|string[]} virPattern glob pattern as string or array of glob patterns for - * virtual directory structure - * @param {object} [options] glob options - * @param {boolean} [options.nodir=true] Do not match directories - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources - */ - byGlob(virPattern, options = { nodir: true }) { - const trace = new Trace(virPattern); - return this._byGlob(virPattern, options, trace).then(function (result) { - trace.printReport(); - return result; - }).then((resources) => { - if (resources.length > 1) { - // Pseudo randomize result order to prevent consumers from relying on it: - // Swap the first object with a randomly chosen one - const x = 0; - const y = randomInt(0, resources.length - 1); - // Swap object at index "x" with "y" - resources[x] = [resources[y], resources[y] = resources[x]][0]; - } - return resources; - }); - } - /** - * Locates resources by matching a given path. - * - * @public - * @param {string} virPath Virtual path - * @param {object} [options] Options - * @param {boolean} [options.nodir=true] Do not match directories - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource - */ - byPath(virPath, options = { nodir: true }) { - const trace = new Trace(virPath); - return this._byPath(virPath, options, trace).then(function (resource) { - trace.printReport(); - return resource; - }); - } - /** - * Locates resources by one or more glob patterns. - * - * @abstract - * @protected - * @param {string|string[]} virPattern glob pattern as string or an array of - * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources - */ - _byGlob(virPattern, options, trace) { - throw new Error("Function '_byGlob' is not implemented"); - } - /** - * Locate resources by matching a single glob pattern. - * - * @abstract - * @protected - * @param {string} pattern glob pattern - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources - */ - _runGlob(pattern, options, trace) { - throw new Error("Function '_runGlob' is not implemented"); - } - /** - * Locates resources by path. - * - * @abstract - * @protected - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource - */ - _byPath(virPath, options, trace) { - throw new Error("Function '_byPath' is not implemented"); - } -} -export default AbstractReader; -//# sourceMappingURL=AbstractReader.js.map \ No newline at end of file diff --git a/lib/AbstractReader.js.map b/lib/AbstractReader.js.map deleted file mode 100644 index 7fe74331..00000000 --- a/lib/AbstractReader.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"AbstractReader.js","sourceRoot":"","sources":["../src/AbstractReader.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,MAAM,oBAAoB,CAAC;AAEvC;;;;;;;GAOG;AACH,MAAM,cAAc;IACnB;;;;;OAKG;IACH,YAAY,IAAI;QACf,IAAI,GAAG,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;YACnC,MAAM,IAAI,SAAS,CAAC,oCAAoC,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,OAAO;QACN,OAAO,IAAI,CAAC,KAAK,IAAI,YAAY,IAAI,CAAC,WAAW,CAAC,IAAI,UAAU,CAAC;IAClE,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,UAAU,EAAE,OAAO,GAAG,EAAC,KAAK,EAAE,IAAI,EAAC;QACzC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,UAAS,MAAM;YACnE,KAAK,CAAC,WAAW,EAAE,CAAC;YACpB,OAAO,MAAM,CAAC;QACf,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;YACrB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,yEAAyE;gBACzE,mDAAmD;gBACnD,MAAM,CAAC,GAAG,CAAC,CAAC;gBACZ,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAC7C,qCAAqC;gBACrC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,GAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7D,CAAC;YACD,OAAO,SAAS,CAAC;QAClB,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,EAAC,KAAK,EAAE,IAAI,EAAC;QACtC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,UAAS,QAAQ;YAClE,KAAK,CAAC,WAAW,EAAE,CAAC;YACpB,OAAO,QAAQ,CAAC;QACjB,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;;;OAUG;IACH,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK;QACjC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC1D,CAAC;IAED;;;;;;;;;OASG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC/B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC3D,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC1D,CAAC;CACD;AAED,eAAe,cAAc,CAAC"} \ No newline at end of file diff --git a/lib/AbstractReaderWriter.js b/lib/AbstractReaderWriter.js deleted file mode 100644 index 720ae73d..00000000 --- a/lib/AbstractReaderWriter.js +++ /dev/null @@ -1,67 +0,0 @@ -import AbstractReader from "./AbstractReader.js"; -/** - * Abstract resource locator implementing the general API for reading and writing resources - * - * @abstract - * @public - * @class - * @alias @ui5/fs/AbstractReaderWriter - * @extends @ui5/fs/AbstractReader - */ -class AbstractReaderWriter extends AbstractReader { - /** - * The constructor. - * - * @public - * @param {string} name Name of the reader/writer. Typically used for tracing purposes - */ - constructor(name) { - if (new.target === AbstractReaderWriter) { - throw new TypeError("Class 'AbstractReaderWriter' is abstract"); - } - super(name); - } - /* - * Returns the name of the reader/writer instance. This can be used for logging/tracing purposes. - * - * @returns {string} Name of the reader/writer - */ - getName() { - return this._name || ``; - } - /** - * Writes the content of a resource to a path. - * - * @public - * @param {@ui5/fs/Resource} resource Resource to write - * @param {object} [options] - * @param {boolean} [options.readOnly=false] Whether the resource content shall be written read-only - * Do not use in conjunction with the drain option. - * The written file will be used as the new source of this resources content. - * Therefore the written file should not be altered by any means. - * Activating this option might improve overall memory consumption. - * @param {boolean} [options.drain=false] Whether the resource content shall be emptied during the write process. - * Do not use in conjunction with the readOnly option. - * Activating this option might improve overall memory consumption. - * This should be used in cases where this is the last access to the resource. - * E.g. the final write of a resource after all processing is finished. - * @returns {Promise} Promise resolving once data has been written - */ - write(resource, options = { drain: false, readOnly: false }) { - return this._write(resource, options); - } - /** - * Writes the content of a resource to a path. - * - * @abstract - * @protected - * @param {@ui5/fs/Resource} resource Resource to write - * @param {object} [options] Write options, see above - * @returns {Promise} Promise resolving once data has been written - */ - _write(resource, options) { - throw new Error("Not implemented"); - } -} -export default AbstractReaderWriter; -//# sourceMappingURL=AbstractReaderWriter.js.map \ No newline at end of file diff --git a/lib/AbstractReaderWriter.js.map b/lib/AbstractReaderWriter.js.map deleted file mode 100644 index d9adb158..00000000 --- a/lib/AbstractReaderWriter.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"AbstractReaderWriter.js","sourceRoot":"","sources":["../src/AbstractReaderWriter.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,oBAAqB,SAAQ,cAAc;IAChD;;;;;OAKG;IACH,YAAY,IAAI;QACf,IAAI,GAAG,CAAC,MAAM,KAAK,oBAAoB,EAAE,CAAC;YACzC,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;QACjE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,CAAC;IACb,CAAC;IAED;;;;OAIG;IACH,OAAO;QACN,OAAO,IAAI,CAAC,KAAK,IAAI,YAAY,IAAI,CAAC,WAAW,CAAC,IAAI,iBAAiB,CAAC;IACzE,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,QAAQ,EAAE,OAAO,GAAG,EAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAC;QACxD,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,QAAQ,EAAE,OAAO;QACvB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACpC,CAAC;CACD;AAED,eAAe,oBAAoB,CAAC"} \ No newline at end of file diff --git a/lib/DuplexCollection.js b/lib/DuplexCollection.js deleted file mode 100644 index 5a167354..00000000 --- a/lib/DuplexCollection.js +++ /dev/null @@ -1,77 +0,0 @@ -import AbstractReaderWriter from "./AbstractReaderWriter.js"; -import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; -/** - * Wrapper to keep readers and writers together - * - * @public - * @class - * @alias @ui5/fs/DuplexCollection - * @extends @ui5/fs/AbstractReaderWriter - */ -class DuplexCollection extends AbstractReaderWriter { - /** - * The Constructor. - * - * @param {object} parameters - * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers - * @param {@ui5/fs/AbstractReaderWriter} parameters.writer - * A ReaderWriter instance which is only used for writing files - * @param {string} [parameters.name=""] The collection name - */ - constructor({ reader, writer, name = "" }) { - super(name); - if (!reader) { - throw new Error(`Cannot create DuplexCollection ${this._name}: No reader provided`); - } - if (!writer) { - throw new Error(`Cannot create DuplexCollection ${this._name}: No writer provided`); - } - this._reader = reader; - this._writer = writer; - this._combo = new ReaderCollectionPrioritized({ - name: `${name} - ReaderCollectionPrioritized`, - readers: [ - writer, - reader - ] - }); - } - /** - * Locates resources by glob. - * - * @private - * @param {string|string[]} virPattern glob pattern as string or an array of - * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving with a list of resources - */ - _byGlob(virPattern, options, trace) { - return this._combo._byGlob(virPattern, options, trace); - } - /** - * Locates resources by path. - * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource|null>} - * Promise resolving to a single resource or null if no resource is found - */ - _byPath(virPath, options, trace) { - return this._combo._byPath(virPath, options, trace); - } - /** - * Writes the content of a resource to a path. - * - * @private - * @param {@ui5/fs/Resource} resource The Resource to write - * @returns {Promise} Promise resolving once data has been written - */ - _write(resource) { - return this._writer.write(resource); - } -} -export default DuplexCollection; -//# sourceMappingURL=DuplexCollection.js.map \ No newline at end of file diff --git a/lib/DuplexCollection.js.map b/lib/DuplexCollection.js.map deleted file mode 100644 index 9f7fad5f..00000000 --- a/lib/DuplexCollection.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"DuplexCollection.js","sourceRoot":"","sources":["../src/DuplexCollection.ts"],"names":[],"mappings":"AAAA,OAAO,oBAAoB,MAAM,2BAA2B,CAAC;AAC7D,OAAO,2BAA2B,MAAM,kCAAkC,CAAC;AAE3E;;;;;;;GAOG;AACH,MAAM,gBAAiB,SAAQ,oBAAoB;IAClD;;;;;;;;OAQG;IACH,YAAY,EAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE,EAAC;QACtC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEZ,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,CAAC,KAAK,sBAAsB,CAAC,CAAC;QACrF,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,CAAC,KAAK,sBAAsB,CAAC,CAAC;QACrF,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QAEtB,IAAI,CAAC,MAAM,GAAG,IAAI,2BAA2B,CAAC;YAC7C,IAAI,EAAE,GAAG,IAAI,gCAAgC;YAC7C,OAAO,EAAE;gBACR,MAAM;gBACN,MAAM;aACN;SACD,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK;QACjC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;CACD;AAED,eAAe,gBAAgB,CAAC"} \ No newline at end of file diff --git a/lib/ReaderCollection.js b/lib/ReaderCollection.js deleted file mode 100644 index 4e644783..00000000 --- a/lib/ReaderCollection.js +++ /dev/null @@ -1,81 +0,0 @@ -import AbstractReader from "./AbstractReader.js"; -/** - * Resource Locator ReaderCollection - * - * @public - * @class - * @alias @ui5/fs/ReaderCollection - * @extends @ui5/fs/AbstractReader - */ -class ReaderCollection extends AbstractReader { - /** - * The constructor. - * - * @param {object} parameters Parameters - * @param {string} parameters.name The collection name - * @param {@ui5/fs/AbstractReader[]} [parameters.readers] - * List of resource readers (all tried in parallel). - * If none are provided, the collection will never return any results. - */ - constructor({ name, readers }) { - super(name); - // Remove any undefined (empty) readers from array - this._readers = readers.filter(($) => $); - } - /** - * Locates resources by glob. - * - * @private - * @param {string|string[]} pattern glob pattern as string or an array of - * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources - */ - _byGlob(pattern, options, trace) { - return Promise.all(this._readers.map(function (resourceLocator) { - return resourceLocator._byGlob(pattern, options, trace); - })).then((result) => { - trace.collection(this._name); - return Array.prototype.concat.apply([], result); - }); - } - /** - * Locates resources by path. - * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource|null>} - * Promise resolving to a single resource or null if no resource is found - */ - _byPath(virPath, options, trace) { - const that = this; - const resourceLocatorCount = this._readers.length; - let resolveCount = 0; - if (resourceLocatorCount === 0) { - // Short-circuit if there are no readers (Promise.race does not settle for empty arrays) - trace.collection(that._name); - return Promise.resolve(null); - } - // Using Promise.race to deliver files that can be found as fast as possible - return Promise.race(this._readers.map(function (resourceLocator) { - return resourceLocator._byPath(virPath, options, trace).then(function (resource) { - return new Promise(function (resolve, reject) { - trace.collection(that._name); - resolveCount++; - if (resource) { - resource.pushCollection(that._name); - resolve(resource); - } - else if (resolveCount === resourceLocatorCount) { - resolve(null); - } - }); - }); - })); - } -} -export default ReaderCollection; -//# sourceMappingURL=ReaderCollection.js.map \ No newline at end of file diff --git a/lib/ReaderCollection.js.map b/lib/ReaderCollection.js.map deleted file mode 100644 index 563f6264..00000000 --- a/lib/ReaderCollection.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ReaderCollection.js","sourceRoot":"","sources":["../src/ReaderCollection.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,gBAAiB,SAAQ,cAAc;IAC5C;;;;;;;;OAQG;IACH,YAAY,EAAC,IAAI,EAAE,OAAO,EAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,CAAC;QAEZ,kDAAkD;QAClD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAS,eAAe;YAC5D,OAAO,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACnB,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,OAAO,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,MAAM,oBAAoB,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAClD,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,IAAI,oBAAoB,KAAK,CAAC,EAAE,CAAC;YAChC,wFAAwF;YACxF,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;QAED,4EAA4E;QAC5E,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAS,eAAe;YAC7D,OAAO,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,UAAS,QAAQ;gBAC7E,OAAO,IAAI,OAAO,CAAC,UAAS,OAAO,EAAE,MAAM;oBAC1C,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAC7B,YAAY,EAAE,CAAC;oBACf,IAAI,QAAQ,EAAE,CAAC;wBACd,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;wBACpC,OAAO,CAAC,QAAQ,CAAC,CAAC;oBACnB,CAAC;yBAAM,IAAI,YAAY,KAAK,oBAAoB,EAAE,CAAC;wBAClD,OAAO,CAAC,IAAI,CAAC,CAAC;oBACf,CAAC;gBACF,CAAC,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC,CAAC;IACL,CAAC;CACD;AAED,eAAe,gBAAgB,CAAC"} \ No newline at end of file diff --git a/lib/ReaderCollectionPrioritized.js b/lib/ReaderCollectionPrioritized.js deleted file mode 100644 index 993a372c..00000000 --- a/lib/ReaderCollectionPrioritized.js +++ /dev/null @@ -1,86 +0,0 @@ -import AbstractReader from "./AbstractReader.js"; -/** - * Prioritized Resource Locator Collection - * - * @public - * @class - * @alias @ui5/fs/ReaderCollectionPrioritized - * @extends @ui5/fs/AbstractReader - */ -class ReaderCollectionPrioritized extends AbstractReader { - /** - * The constructor. - * - * @param {object} parameters - * @param {string} parameters.name The collection name - * @param {@ui5/fs/AbstractReader[]} [parameters.readers] - * Prioritized list of resource readers (tried in the order provided). - * If none are provided, the collection will never return any results. - */ - constructor({ readers, name }) { - super(name); - // Remove any undefined (empty) readers from array - this._readers = readers.filter(($) => $); - } - /** - * Locates resources by glob. - * - * @private - * @param {string|string[]} pattern glob pattern as string or an array of - * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources - */ - _byGlob(pattern, options, trace) { - return Promise.all(this._readers.map(function (resourceLocator) { - return resourceLocator._byGlob(pattern, options, trace); - })).then((result) => { - const files = Object.create(null); - const resources = []; - // Prefer files found in preceding resource locators - for (let i = 0; i < result.length; i++) { - for (let j = 0; j < result[i].length; j++) { - const resource = result[i][j]; - const path = resource.getPath(); - if (!files[path]) { - files[path] = true; - resources.push(resource); - } - } - } - trace.collection(this._name); - return resources; - }); - } - /** - * Locates resources by path. - * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource|null>} - * Promise resolving to a single resource or null if no resource is found - */ - _byPath(virPath, options, trace) { - const that = this; - const byPath = (i) => { - if (i > this._readers.length - 1) { - return null; - } - return this._readers[i]._byPath(virPath, options, trace).then((resource) => { - if (resource) { - resource.pushCollection(that._name); - return resource; - } - else { - return byPath(++i); - } - }); - }; - return byPath(0); - } -} -export default ReaderCollectionPrioritized; -//# sourceMappingURL=ReaderCollectionPrioritized.js.map \ No newline at end of file diff --git a/lib/ReaderCollectionPrioritized.js.map b/lib/ReaderCollectionPrioritized.js.map deleted file mode 100644 index d3a68304..00000000 --- a/lib/ReaderCollectionPrioritized.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ReaderCollectionPrioritized.js","sourceRoot":"","sources":["../src/ReaderCollectionPrioritized.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,2BAA4B,SAAQ,cAAc;IACvD;;;;;;;;OAQG;IACH,YAAY,EAAC,OAAO,EAAE,IAAI,EAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,CAAC;QAEZ,kDAAkD;QAClD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAS,eAAe;YAC5D,OAAO,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACnB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,SAAS,GAAG,EAAE,CAAC;YACrB,oDAAoD;YACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC3C,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;oBAChC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;wBAClB,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;wBACnB,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC1B,CAAC;gBACF,CAAC;YACF,CAAC;YAED,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,OAAO,SAAS,CAAC;QAClB,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE;YACpB,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,OAAO,IAAI,CAAC;YACb,CAAC;YACD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;gBAC1E,IAAI,QAAQ,EAAE,CAAC;oBACd,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACpC,OAAO,QAAQ,CAAC;gBACjB,CAAC;qBAAM,CAAC;oBACP,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;gBACpB,CAAC;YACF,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC;QACF,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;CACD;AAED,eAAe,2BAA2B,CAAC"} \ No newline at end of file diff --git a/lib/Resource.js b/lib/Resource.js deleted file mode 100644 index c7616041..00000000 --- a/lib/Resource.js +++ /dev/null @@ -1,463 +0,0 @@ -import stream from "node:stream"; -import clone from "clone"; -import posixPath from "node:path/posix"; -const fnTrue = () => true; -const fnFalse = () => false; -const ALLOWED_SOURCE_METADATA_KEYS = ["adapter", "fsPath", "contentModified"]; -/** - * Resource. UI5 Tooling specific representation of a file's content and metadata - * - * @public - * @class - * @alias @ui5/fs/Resource - */ -class Resource { - #project; - #buffer; - #buffering; - #collections; - #contentDrained; - #createStream; - #name; - #path; - #sourceMetadata; - #statInfo; - #stream; - #streamDrained; - #isModified; - /** - * Function for dynamic creation of content streams - * - * @public - * @callback @ui5/fs/Resource~createStream - * @returns {stream.Readable} A readable stream of a resources content - */ - /** - * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.path Absolute virtual path of the resource - * @param {fs.Stats|object} [parameters.statInfo] File information. Instance of - * [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} or similar object - * @param {Buffer} [parameters.buffer] Content of this resources as a Buffer instance - * (cannot be used in conjunction with parameters string, stream or createStream) - * @param {string} [parameters.string] Content of this resources as a string - * (cannot be used in conjunction with parameters buffer, stream or createStream) - * @param {Stream} [parameters.stream] Readable stream of the content of this resource - * (cannot be used in conjunction with parameters buffer, string or createStream) - * @param {@ui5/fs/Resource~createStream} [parameters.createStream] Function callback that returns a readable - * stream of the content of this resource (cannot be used in conjunction with parameters buffer, - * string or stream). - * In some cases this is the most memory-efficient way to supply resource content - * @param {@ui5/project/specifications/Project} [parameters.project] Project this resource is associated with - * @param {object} [parameters.sourceMetadata] Source metadata for UI5 Tooling internal use. - * Some information may be set by an adapter to store information for later retrieval. Also keeps track of whether - * a resource content has been modified since it has been read from a source - */ - constructor({ path, statInfo, buffer, string, createStream, stream, project, sourceMetadata }) { - if (!path) { - throw new Error("Unable to create Resource: Missing parameter 'path'"); - } - if (buffer && createStream || buffer && string || string && createStream || buffer && stream || - string && stream || createStream && stream) { - throw new Error("Unable to create Resource: Please set only one content parameter. " + - "'buffer', 'string', 'stream' or 'createStream'"); - } - if (sourceMetadata) { - if (typeof sourceMetadata !== "object") { - throw new Error(`Parameter 'sourceMetadata' must be of type "object"`); - } - /* eslint-disable-next-line guard-for-in */ - for (const metadataKey in sourceMetadata) { // Also check prototype - if (!ALLOWED_SOURCE_METADATA_KEYS.includes(metadataKey)) { - throw new Error(`Parameter 'sourceMetadata' contains an illegal attribute: ${metadataKey}`); - } - if (!["string", "boolean"].includes(typeof sourceMetadata[metadataKey])) { - throw new Error(`Attribute '${metadataKey}' of parameter 'sourceMetadata' ` + - `must be of type "string" or "boolean"`); - } - } - } - this.setPath(path); - this.#sourceMetadata = sourceMetadata || {}; - // This flag indicates whether a resource has changed from its original source. - // resource.isModified() is not sufficient, since it only reflects the modification state of the - // current instance. - // Since the sourceMetadata object is inherited to clones, it is the only correct indicator - this.#sourceMetadata.contentModified ??= false; - this.#isModified = false; - this.#project = project; - this.#statInfo = statInfo || { - isFile: fnTrue, - isDirectory: fnFalse, - isBlockDevice: fnFalse, - isCharacterDevice: fnFalse, - isSymbolicLink: fnFalse, - isFIFO: fnFalse, - isSocket: fnFalse, - atimeMs: new Date().getTime(), - mtimeMs: new Date().getTime(), - ctimeMs: new Date().getTime(), - birthtimeMs: new Date().getTime(), - atime: new Date(), - mtime: new Date(), - ctime: new Date(), - birthtime: new Date() - }; - if (createStream) { - this.#createStream = createStream; - } - else if (stream) { - this.#stream = stream; - } - else if (buffer) { - // Use private setter, not to accidentally set any modified flags - this.#setBuffer(buffer); - } - else if (typeof string === "string" || string instanceof String) { - // Use private setter, not to accidentally set any modified flags - this.#setBuffer(Buffer.from(string, "utf8")); - } - // Tracing: - this.#collections = []; - } - /** - * Gets a buffer with the resource content. - * - * @public - * @returns {Promise} Promise resolving with a buffer of the resource content. - */ - async getBuffer() { - if (this.#contentDrained) { - throw new Error(`Content of Resource ${this.#path} has been drained. ` + - "This might be caused by requesting resource content after a content stream has been " + - "requested and no new content (e.g. a new stream) has been set."); - } - if (this.#buffer) { - return this.#buffer; - } - else if (this.#createStream || this.#stream) { - return this.#getBufferFromStream(); - } - else { - throw new Error(`Resource ${this.#path} has no content`); - } - } - /** - * Sets a Buffer as content. - * - * @public - * @param {Buffer} buffer Buffer instance - */ - setBuffer(buffer) { - this.#sourceMetadata.contentModified = true; - this.#isModified = true; - this.#setBuffer(buffer); - } - #setBuffer(buffer) { - this.#createStream = null; - // if (this.#stream) { // TODO this may cause strange issues - // this.#stream.destroy(); - // } - this.#stream = null; - this.#buffer = buffer; - this.#contentDrained = false; - this.#streamDrained = false; - } - /** - * Gets a string with the resource content. - * - * @public - * @returns {Promise} Promise resolving with the resource content. - */ - getString() { - if (this.#contentDrained) { - return Promise.reject(new Error(`Content of Resource ${this.#path} has been drained. ` + - "This might be caused by requesting resource content after a content stream has been " + - "requested and no new content (e.g. a new stream) has been set.")); - } - return this.getBuffer().then((buffer) => buffer.toString()); - } - /** - * Sets a String as content - * - * @public - * @param {string} string Resource content - */ - setString(string) { - this.setBuffer(Buffer.from(string, "utf8")); - } - /** - * Gets a readable stream for the resource content. - * - * Repetitive calls of this function are only possible if new content has been set in the meantime (through - * [setStream]{@link @ui5/fs/Resource#setStream}, [setBuffer]{@link @ui5/fs/Resource#setBuffer} - * or [setString]{@link @ui5/fs/Resource#setString}). This - * is to prevent consumers from accessing drained streams. - * - * @public - * @returns {stream.Readable} Readable stream for the resource content. - */ - getStream() { - if (this.#contentDrained) { - throw new Error(`Content of Resource ${this.#path} has been drained. ` + - "This might be caused by requesting resource content after a content stream has been " + - "requested and no new content (e.g. a new stream) has been set."); - } - let contentStream; - if (this.#buffer) { - const bufferStream = new stream.PassThrough(); - bufferStream.end(this.#buffer); - contentStream = bufferStream; - } - else if (this.#createStream || this.#stream) { - contentStream = this.#getStream(); - } - if (!contentStream) { - throw new Error(`Resource ${this.#path} has no content`); - } - // If a stream instance is being returned, it will typically get drained be the consumer. - // In that case, further content access will result in a "Content stream has been drained" error. - // However, depending on the execution environment, a resources content stream might have been - // transformed into a buffer. In that case further content access is possible as a buffer can't be - // drained. - // To prevent unexpected "Content stream has been drained" errors caused by changing environments, we flag - // the resource content as "drained" every time a stream is requested. Even if actually a buffer or - // createStream callback is being used. - this.#contentDrained = true; - return contentStream; - } - /** - * Sets a readable stream as content. - * - * @public - * @param {stream.Readable|@ui5/fs/Resource~createStream} stream Readable stream of the resource content or - callback for dynamic creation of a readable stream - */ - setStream(stream) { - this.#isModified = true; - this.#sourceMetadata.contentModified = true; - this.#buffer = null; - // if (this.#stream) { // TODO this may cause strange issues - // this.#stream.destroy(); - // } - if (typeof stream === "function") { - this.#createStream = stream; - this.#stream = null; - } - else { - this.#stream = stream; - this.#createStream = null; - } - this.#contentDrained = false; - this.#streamDrained = false; - } - /** - * Gets the virtual resources path - * - * @public - * @returns {string} Virtual path of the resource - */ - getPath() { - return this.#path; - } - /** - * Sets the virtual resources path - * - * @public - * @param {string} path Absolute virtual path of the resource - */ - setPath(path) { - path = posixPath.normalize(path); - if (!posixPath.isAbsolute(path)) { - throw new Error(`Unable to set resource path: Path must be absolute: ${path}`); - } - this.#path = path; - this.#name = posixPath.basename(path); - } - /** - * Gets the resource name - * - * @public - * @returns {string} Name of the resource - */ - getName() { - return this.#name; - } - /** - * Gets the resources stat info. - * Note that a resources stat information is not updated when the resource is being modified. - * Also, depending on the used adapter, some fields might be missing which would be present for a - * [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} instance. - * - * @public - * @returns {fs.Stats|object} Instance of [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} - * or similar object - */ - getStatInfo() { - return this.#statInfo; - } - /** - * Size in bytes allocated by the underlying buffer. - * - * @see {TypedArray#byteLength} - * @returns {Promise} size in bytes, 0 if there is no content yet - */ - async getSize() { - // if resource does not have any content it should have 0 bytes - if (!this.#buffer && !this.#createStream && !this.#stream) { - return 0; - } - const buffer = await this.getBuffer(); - return buffer.byteLength; - } - /** - * Adds a resource collection name that was involved in locating this resource. - * - * @param {string} name Resource collection name - */ - pushCollection(name) { - this.#collections.push(name); - } - /** - * Returns a clone of the resource. The clones content is independent from that of the original resource - * - * @public - * @returns {Promise<@ui5/fs/Resource>} Promise resolving with the clone - */ - async clone() { - const options = await this.#getCloneOptions(); - return new Resource(options); - } - async #getCloneOptions() { - const options = { - path: this.#path, - statInfo: clone(this.#statInfo), - sourceMetadata: clone(this.#sourceMetadata) - }; - if (this.#stream) { - options.buffer = await this.#getBufferFromStream(); - } - else if (this.#createStream) { - options.createStream = this.#createStream; - } - else if (this.#buffer) { - options.buffer = this.#buffer; - } - return options; - } - /** - * Retrieve the project assigned to the resource - *
- * Note for UI5 Tooling extensions (i.e. custom tasks, custom middleware): - * In order to ensure compatibility across UI5 Tooling versions, consider using the - * getProject(resource) method provided by - * [TaskUtil]{@link module:@ui5/project/build/helpers/TaskUtil} and - * [MiddlewareUtil]{@link module:@ui5/server.middleware.MiddlewareUtil}, which will - * return a Specification Version-compatible Project interface. - * - * @public - * @returns {@ui5/project/specifications/Project} Project this resource is associated with - */ - getProject() { - return this.#project; - } - /** - * Assign a project to the resource - * - * @public - * @param {@ui5/project/specifications/Project} project Project this resource is associated with - */ - setProject(project) { - if (this.#project) { - throw new Error(`Unable to assign project ${project.getName()} to resource ${this.#path}: ` + - `Resource is already associated to project ${this.#project}`); - } - this.#project = project; - } - /** - * Check whether a project has been assigned to the resource - * - * @public - * @returns {boolean} True if the resource is associated with a project - */ - hasProject() { - return !!this.#project; - } - /** - * Check whether the content of this resource has been changed during its life cycle - * - * @public - * @returns {boolean} True if the resource's content has been changed - */ - isModified() { - return this.#isModified; - } - /** - * Tracing: Get tree for printing out trace - * - * @returns {object} Trace tree - */ - getPathTree() { - const tree = Object.create(null); - let pointer = tree[this.#path] = Object.create(null); - for (let i = this.#collections.length - 1; i >= 0; i--) { - pointer = pointer[this.#collections[i]] = Object.create(null); - } - return tree; - } - /** - * Returns source metadata which may contain information specific to the adapter that created the resource - * Typically set by an adapter to store information for later retrieval. - * - * @returns {object} - */ - getSourceMetadata() { - return this.#sourceMetadata; - } - /** - * Returns the content as stream. - * - * @private - * @returns {stream.Readable} Readable stream - */ - #getStream() { - if (this.#streamDrained) { - throw new Error(`Content stream of Resource ${this.#path} is flagged as drained.`); - } - if (this.#createStream) { - return this.#createStream(); - } - this.#streamDrained = true; - return this.#stream; - } - /** - * Converts the buffer into a stream. - * - * @private - * @returns {Promise} Promise resolving with buffer. - */ - #getBufferFromStream() { - if (this.#buffering) { // Prevent simultaneous buffering, causing unexpected access to drained stream - return this.#buffering; - } - return this.#buffering = new Promise((resolve, reject) => { - const contentStream = this.#getStream(); - const buffers = []; - contentStream.on("data", (data) => { - buffers.push(data); - }); - contentStream.on("error", (err) => { - reject(err); - }); - contentStream.on("end", () => { - const buffer = Buffer.concat(buffers); - this.#setBuffer(buffer); - this.#buffering = null; - resolve(buffer); - }); - }); - } -} -export default Resource; -//# sourceMappingURL=Resource.js.map \ No newline at end of file diff --git a/lib/Resource.js.map b/lib/Resource.js.map deleted file mode 100644 index f366b268..00000000 --- a/lib/Resource.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Resource.js","sourceRoot":"","sources":["../src/Resource.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/ResourceFacade.js b/lib/ResourceFacade.js deleted file mode 100644 index 886551ff..00000000 --- a/lib/ResourceFacade.js +++ /dev/null @@ -1,240 +0,0 @@ -import posixPath from "node:path/posix"; -/** - * A {@link @ui5/fs/Resource Resource} with a different path than it's original - * - * @public - * @class - * @alias @ui5/fs/ResourceFacade - */ -class ResourceFacade { - #path; - #name; - #resource; - /** - * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.path Virtual path of the facade resource - * @param {@ui5/fs/Resource} parameters.resource Resource to conceal - */ - constructor({ path, resource }) { - if (!path) { - throw new Error("Unable to create ResourceFacade: Missing parameter 'path'"); - } - if (!resource) { - throw new Error("Unable to create ResourceFacade: Missing parameter 'resource'"); - } - path = posixPath.normalize(path); - if (!posixPath.isAbsolute(path)) { - throw new Error(`Unable to create ResourceFacade: Parameter 'path' must be absolute: ${path}`); - } - this.#path = path; - this.#name = posixPath.basename(path); - this.#resource = resource; - } - /** - * Gets the resources path - * - * @public - * @returns {string} (Virtual) path of the resource - */ - getPath() { - return this.#path; - } - /** - * Gets the resource name - * - * @public - * @returns {string} Name of the resource - */ - getName() { - return this.#name; - } - /** - * Sets the resources path - * - * @public - * @param {string} path (Virtual) path of the resource - */ - setPath(path) { - throw new Error(`The path of a ResourceFacade can't be changed`); - } - /** - * Returns a clone of the resource. The clones content is independent from that of the original resource. - * A ResourceFacade becomes a Resource - * - * @public - * @returns {Promise<@ui5/fs/Resource>} Promise resolving with the clone - */ - async clone() { - // Cloning resolves the facade - const resourceClone = await this.#resource.clone(); - resourceClone.setPath(this.getPath()); - return resourceClone; - } - /** - * ====================================================================== - * Call through functions to original resource - * ====================================================================== - */ - /** - * Gets a buffer with the resource content. - * - * @public - * @returns {Promise} Promise resolving with a buffer of the resource content. - */ - async getBuffer() { - return this.#resource.getBuffer(); - } - /** - * Sets a Buffer as content. - * - * @public - * @param {Buffer} buffer Buffer instance - */ - setBuffer(buffer) { - return this.#resource.setBuffer(buffer); - } - /** - * Gets a string with the resource content. - * - * @public - * @returns {Promise} Promise resolving with the resource content. - */ - getString() { - return this.#resource.getString(); - } - /** - * Sets a String as content - * - * @public - * @param {string} string Resource content - */ - setString(string) { - return this.#resource.setString(string); - } - /** - * Gets a readable stream for the resource content. - * - * Repetitive calls of this function are only possible if new content has been set in the meantime (through - * [setStream]{@link @ui5/fs/Resource#setStream}, [setBuffer]{@link @ui5/fs/Resource#setBuffer} - * or [setString]{@link @ui5/fs/Resource#setString}). This - * is to prevent consumers from accessing drained streams. - * - * @public - * @returns {stream.Readable} Readable stream for the resource content. - */ - getStream() { - return this.#resource.getStream(); - } - /** - * Sets a readable stream as content. - * - * @public - * @param {stream.Readable|@ui5/fs/Resource~createStream} stream Readable stream of the resource content or - callback for dynamic creation of a readable stream - */ - setStream(stream) { - return this.#resource.setStream(stream); - } - /** - * Gets the resources stat info. - * Note that a resources stat information is not updated when the resource is being modified. - * Also, depending on the used adapter, some fields might be missing which would be present for a - * [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} instance. - * - * @public - * @returns {fs.Stats|object} Instance of [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} - * or similar object - */ - getStatInfo() { - return this.#resource.getStatInfo(); - } - /** - * Size in bytes allocated by the underlying buffer. - * - * @see {TypedArray#byteLength} - * @returns {Promise} size in bytes, 0 if there is no content yet - */ - async getSize() { - return this.#resource.getSize(); - } - /** - * Adds a resource collection name that was involved in locating this resource. - * - * @param {string} name Resource collection name - */ - pushCollection(name) { - return this.#resource.pushCollection(name); - } - /** - * Tracing: Get tree for printing out trace - * - * @returns {object} Trace tree - */ - getPathTree() { - return this.#resource.getPathTree(); - } - /** - * Retrieve the project assigned to the resource - *
- * Note for UI5 Tooling extensions (i.e. custom tasks, custom middleware): - * In order to ensure compatibility across UI5 Tooling versions, consider using the - * getProject(resource) method provided by - * [TaskUtil]{@link module:@ui5/project/build/helpers/TaskUtil} and - * [MiddlewareUtil]{@link module:@ui5/server.middleware.MiddlewareUtil}, which will - * return a Specification Version-compatible Project interface. - * - * @public - * @returns {@ui5/project/specifications/Project} Project this resource is associated with - */ - getProject() { - return this.#resource.getProject(); - } - /** - * Assign a project to the resource - * - * @public - * @param {@ui5/project/specifications/Project} project Project this resource is associated with - */ - setProject(project) { - return this.#resource.setProject(project); - } - /** - * Check whether a project has been assigned to the resource - * - * @public - * @returns {boolean} True if the resource is associated with a project - */ - hasProject() { - return this.#resource.hasProject(); - } - /** - * Check whether the content of this resource has been changed during its life cycle - * - * @public - * @returns {boolean} True if the resource's content has been changed - */ - isModified() { - return this.#resource.isModified(); - } - /** - * Returns source metadata if any where provided during the creation of this resource. - * Typically set by an adapter to store information for later retrieval. - * - * @returns {object|null} - */ - getSourceMetadata() { - return this.#resource.getSourceMetadata(); - } - /** - * Returns the resource concealed by this facade - * - * @returns {@ui5/fs/Resource} - */ - getConcealedResource() { - return this.#resource; - } -} -export default ResourceFacade; -//# sourceMappingURL=ResourceFacade.js.map \ No newline at end of file diff --git a/lib/ResourceFacade.js.map b/lib/ResourceFacade.js.map deleted file mode 100644 index fd68e837..00000000 --- a/lib/ResourceFacade.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ResourceFacade.js","sourceRoot":"","sources":["../src/ResourceFacade.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/ResourceTagCollection.js b/lib/ResourceTagCollection.js deleted file mode 100644 index 7867666c..00000000 --- a/lib/ResourceTagCollection.js +++ /dev/null @@ -1,107 +0,0 @@ -const tagNamespaceRegExp = /^[a-z][a-z0-9]+$/; // part before the colon -const tagNameRegExp = /^[A-Z][A-Za-z0-9]+$/; // part after the colon -import ResourceFacade from "./ResourceFacade.js"; -/** - * A ResourceTagCollection - * - * @private - * @class - * @alias @ui5/fs/internal/ResourceTagCollection - */ -class ResourceTagCollection { - constructor({ allowedTags = [], allowedNamespaces = [], tags }) { - this._allowedTags = allowedTags; // Allowed tags are validated during use - this._allowedNamespaces = allowedNamespaces; - if (allowedNamespaces.length) { - let allowedNamespacesRegExp = allowedNamespaces.reduce((regex, tagNamespace, idx) => { - // Ensure alphanum namespace to ensure working regex - if (!tagNamespaceRegExp.test(tagNamespace)) { - throw new Error(`Invalid namespace ${tagNamespace}: ` + - `Namespace must be alphanumeric, lowercase and start with a letter`); - } - return `${regex}${idx === 0 ? "" : "|"}${tagNamespace}`; - }, "^(?:"); - allowedNamespacesRegExp += "):.+$"; - this._allowedNamespacesRegExp = new RegExp(allowedNamespacesRegExp); - } - else { - this._allowedNamespacesRegExp = null; - } - this._pathTags = tags || Object.create(null); - } - setTag(resourcePath, tag, value = true) { - resourcePath = this._getPath(resourcePath); - this._validateTag(tag); - this._validateValue(value); - if (!this._pathTags[resourcePath]) { - this._pathTags[resourcePath] = Object.create(null); - } - this._pathTags[resourcePath][tag] = value; - } - clearTag(resourcePath, tag) { - resourcePath = this._getPath(resourcePath); - this._validateTag(tag); - if (this._pathTags[resourcePath]) { - this._pathTags[resourcePath][tag] = undefined; - } - } - getTag(resourcePath, tag) { - resourcePath = this._getPath(resourcePath); - this._validateTag(tag); - if (this._pathTags[resourcePath]) { - return this._pathTags[resourcePath][tag]; - } - } - getAllTags() { - return this._pathTags; - } - acceptsTag(tag) { - if (this._allowedTags.includes(tag) || this._allowedNamespacesRegExp?.test(tag)) { - return true; - } - return false; - } - _getPath(resourcePath) { - if (typeof resourcePath !== "string") { - if (resourcePath instanceof ResourceFacade) { - resourcePath = resourcePath.getConcealedResource().getPath(); - } - else { - resourcePath = resourcePath.getPath(); - } - } - if (!resourcePath) { - throw new Error(`Invalid Resource: Resource path must not be empty`); - } - return resourcePath; - } - _validateTag(tag) { - if (!tag.includes(":")) { - throw new Error(`Invalid Tag "${tag}": Colon required after namespace`); - } - const parts = tag.split(":"); - if (parts.length > 2) { - throw new Error(`Invalid Tag "${tag}": Expected exactly one colon but found ${parts.length - 1}`); - } - const [tagNamespace, tagName] = parts; - if (!tagNamespaceRegExp.test(tagNamespace)) { - throw new Error(`Invalid Tag "${tag}": Namespace part must be alphanumeric, lowercase and start with a letter`); - } - if (!tagNameRegExp.test(tagName)) { - throw new Error(`Invalid Tag "${tag}": Name part must be alphanumeric and start with a capital letter`); - } - if (!this.acceptsTag(tag)) { - throw new Error(`Tag "${tag}" not accepted by this collection. Accepted tags are: ` + - `${this._allowedTags.join(", ") || "*none*"}. Accepted namespaces are: ` + - `${this._allowedNamespaces.join(", ") || "*none*"}`); - } - } - _validateValue(value) { - const type = typeof value; - if (!["string", "number", "boolean"].includes(type)) { - throw new Error(`Invalid Tag Value: Must be of type string, number or boolean but is ${type}`); - } - } -} -export default ResourceTagCollection; -//# sourceMappingURL=ResourceTagCollection.js.map \ No newline at end of file diff --git a/lib/ResourceTagCollection.js.map b/lib/ResourceTagCollection.js.map deleted file mode 100644 index ed5cd63e..00000000 --- a/lib/ResourceTagCollection.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ResourceTagCollection.js","sourceRoot":"","sources":["../src/ResourceTagCollection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/WriterCollection.js b/lib/WriterCollection.js deleted file mode 100644 index 1985e53e..00000000 --- a/lib/WriterCollection.js +++ /dev/null @@ -1,105 +0,0 @@ -import AbstractReaderWriter from "./AbstractReaderWriter.js"; -import ReaderCollection from "./ReaderCollection.js"; -import escapeStringRegExp from "escape-string-regexp"; -/** - * Resource Locator WriterCollection - * - * @public - * @class - * @alias @ui5/fs/WriterCollection - * @extends @ui5/fs/AbstractReaderWriter - */ -class WriterCollection extends AbstractReaderWriter { - /** - * The constructor. - * - * @param {object} parameters Parameters - * @param {string} parameters.name The collection name - * @param {object.} parameters.writerMapping - * Mapping of virtual base paths to writers. Path are matched greedy - * - * @example - * new WriterCollection({ - * name: "Writer Collection", - * writerMapping: { - * "/": writerA, - * "/my/path/": writerB, - * } - * }); - */ - constructor({ name, writerMapping }) { - super(name); - if (!writerMapping) { - throw new Error(`Cannot create WriterCollection ${this._name}: Missing parameter 'writerMapping'`); - } - const basePaths = Object.keys(writerMapping); - if (!basePaths.length) { - throw new Error(`Cannot create WriterCollection ${this._name}: Empty parameter 'writerMapping'`); - } - // Create a regular expression (which is greedy by nature) from all paths to easily - // find the correct writer for any given resource path - this._basePathRegex = basePaths.sort().reduce((regex, basePath, idx) => { - // Validate base path - if (!basePath) { - throw new Error(`Empty path in path mapping of WriterCollection ${this._name}`); - } - if (!basePath.startsWith("/")) { - throw new Error(`Missing leading slash in path mapping '${basePath}' of WriterCollection ${this._name}`); - } - if (!basePath.endsWith("/")) { - throw new Error(`Missing trailing slash in path mapping '${basePath}' of WriterCollection ${this._name}`); - } - return `${regex}(?:${escapeStringRegExp(basePath)})??`; - }, "^(") + ")+.*?$"; - this._writerMapping = writerMapping; - this._readerCollection = new ReaderCollection({ - name: `Reader collection of writer collection '${this._name}'`, - readers: Object.values(writerMapping) - }); - } - /** - * Locates resources by glob. - * - * @private - * @param {string|string[]} pattern glob pattern as string or an array of - * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources - */ - _byGlob(pattern, options, trace) { - return this._readerCollection._byGlob(pattern, options, trace); - } - /** - * Locates resources by path. - * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource - */ - _byPath(virPath, options, trace) { - return this._readerCollection._byPath(virPath, options, trace); - } - /** - * Writes the content of a resource to a path. - * - * @private - * @param {@ui5/fs/Resource} resource The Resource to write - * @param {object} [options] Write options, see above - * @returns {Promise} Promise resolving once data has been written - */ - _write(resource, options) { - const resourcePath = resource.getPath(); - const basePathMatch = resourcePath.match(this._basePathRegex); - if (!basePathMatch || basePathMatch.length < 2) { - throw new Error(`Failed to find a writer for resource with path ${resourcePath} in WriterCollection ${this._name}. ` + - `Base paths handled by this collection are: ${Object.keys(this._writerMapping).join(", ")}`); - } - const writer = this._writerMapping[basePathMatch[1]]; - return writer._write(resource, options); - } -} -export default WriterCollection; -//# sourceMappingURL=WriterCollection.js.map \ No newline at end of file diff --git a/lib/WriterCollection.js.map b/lib/WriterCollection.js.map deleted file mode 100644 index 9ac8dbca..00000000 --- a/lib/WriterCollection.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"WriterCollection.js","sourceRoot":"","sources":["../src/WriterCollection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/adapters/AbstractAdapter.js b/lib/adapters/AbstractAdapter.js deleted file mode 100644 index a61f9156..00000000 --- a/lib/adapters/AbstractAdapter.js +++ /dev/null @@ -1,280 +0,0 @@ -import path from "node:path/posix"; -import { getLogger } from "@ui5/logger"; -const log = getLogger("resources:adapters:AbstractAdapter"); -import { minimatch } from "minimatch"; -import micromatch from "micromatch"; -import AbstractReaderWriter from "../AbstractReaderWriter.js"; -import Resource from "../Resource.js"; -/** - * Abstract Resource Adapter - * - * @abstract - * @public - * @class - * @alias @ui5/fs/adapters/AbstractAdapter - * @extends @ui5/fs/AbstractReaderWriter - */ -class AbstractAdapter extends AbstractReaderWriter { - /** - * The constructor - * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.virBasePath - * Virtual base path. Must be absolute, POSIX-style, and must end with a slash - * @param {string[]} [parameters.excludes] List of glob patterns to exclude - * @param {object} [parameters.project] Experimental, internal parameter. Do not use - */ - constructor({ virBasePath, excludes = [], project }) { - if (new.target === AbstractAdapter) { - throw new TypeError("Class 'AbstractAdapter' is abstract"); - } - super(); - if (!virBasePath) { - throw new Error(`Unable to create adapter: Missing parameter 'virBasePath'`); - } - if (!path.isAbsolute(virBasePath)) { - throw new Error(`Unable to create adapter: Virtual base path must be absolute but is '${virBasePath}'`); - } - if (!virBasePath.endsWith("/")) { - throw new Error(`Unable to create adapter: Virtual base path must end with a slash but is '${virBasePath}'`); - } - this._virBasePath = virBasePath; - this._virBaseDir = virBasePath.slice(0, -1); - this._excludes = excludes; - this._excludesNegated = excludes.map((pattern) => `!${pattern}`); - this._project = project; - } - /** - * Locates resources by glob. - * - * @abstract - * @private - * @param {string|string[]} virPattern glob pattern as string or an array of - * glob patterns for virtual directory structure - * @param {object} [options={}] glob options - * @param {boolean} [options.nodir=true] Do not match directories - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources - */ - async _byGlob(virPattern, options = { nodir: true }, trace) { - const excludes = this._excludesNegated; - if (!(virPattern instanceof Array)) { - virPattern = [virPattern]; - } - // Append static exclude patterns - virPattern = Array.prototype.concat.apply(virPattern, excludes); - let patterns = virPattern.map(this._normalizePattern, this); - patterns = Array.prototype.concat.apply([], patterns); - if (patterns.length === 0) { - return []; - } - if (!options.nodir) { - for (let i = patterns.length - 1; i >= 0; i--) { - const idx = this._virBaseDir.indexOf(patterns[i]); - if (patterns[i] && idx !== -1 && idx < this._virBaseDir.length) { - const subPath = patterns[i]; - return [ - this._createResource({ - statInfo: { - isDirectory: function () { - return true; - } - }, - source: { - adapter: "Abstract" - }, - path: subPath - }) - ]; - } - } - } - return await this._runGlob(patterns, options, trace); - } - /** - * Validate if virtual path should be excluded - * - * @param {string} virPath Virtual Path - * @returns {boolean} True if path is excluded, otherwise false - */ - _isPathExcluded(virPath) { - return micromatch(virPath, this._excludes).length > 0; - } - /** - * Validate if virtual path should be handled by the adapter. - * This means that it either starts with the virtual base path of the adapter - * or equals the base directory (base path without a trailing slash) - * - * @param {string} virPath Virtual Path - * @returns {boolean} True if path should be handled - */ - _isPathHandled(virPath) { - // Check whether path starts with base path, or equals base directory - return virPath.startsWith(this._virBasePath) || virPath === this._virBaseDir; - } - /** - * Normalizes virtual glob patterns. - * - * @private - * @param {string} virPattern glob pattern for virtual directory structure - * @returns {string[]} A list of normalized glob patterns - */ - _normalizePattern(virPattern) { - const that = this; - const mm = new minimatch.Minimatch(virPattern); - const basePathParts = this._virBaseDir.split("/"); - function matchSubset(subset) { - let i; - for (i = 0; i < basePathParts.length; i++) { - const globPart = subset[i]; - if (globPart === undefined) { - log.verbose("Ran out of glob parts to match (this should not happen):"); - if (that._project) { // project is optional - log.verbose(`Project: ${that._project.getName()}`); - } - log.verbose(`Virtual base path: ${that._virBaseDir}`); - log.verbose(`Pattern to match: ${virPattern}`); - log.verbose(`Current subset (tried index ${i}):`); - log.verbose(subset); - return { idx: i, virtualMatch: true }; - } - const basePathPart = basePathParts[i]; - if (typeof globPart === "string") { - if (globPart !== basePathPart) { - return null; - } - else { - continue; - } - } - else if (globPart === minimatch.GLOBSTAR) { - return { idx: i }; - } - else { // Regex - if (!globPart.test(basePathPart)) { - return null; - } - else { - continue; - } - } - } - if (subset.length === basePathParts.length) { - return { rootMatch: true }; - } - return { idx: i }; - } - const resultGlobs = []; - for (let i = 0; i < mm.set.length; i++) { - const match = matchSubset(mm.set[i]); - if (match) { - let resultPattern; - if (match.virtualMatch) { - resultPattern = basePathParts.slice(0, match.idx).join("/"); - } - else if (match.rootMatch) { // matched one up - resultPattern = ""; // root "/" - } - else { // matched at some part of the glob - resultPattern = mm.globParts[i].slice(match.idx).join("/"); - if (resultPattern.startsWith("/")) { - resultPattern = resultPattern.substr(1); - } - } - if (mm.negate) { - resultPattern = "!" + resultPattern; - } - resultGlobs.push(resultPattern); - } - } - return resultGlobs; - } - _createResource(parameters) { - if (this._project) { - parameters.project = this._project; - } - return new Resource(parameters); - } - _migrateResource(resource) { - // This function only returns a promise if a migration is necessary. - // Since this is rarely the case, we therefore reduce the amount of - // created Promises by making this differentiation - // Check if its a fs/Resource v3, function 'hasProject' was - // introduced with v3 therefore take it as the indicator - if (resource.hasProject) { - return resource; - } - return this._createFromLegacyResource(resource); - } - async _createFromLegacyResource(resource) { - const options = { - path: resource._path, - statInfo: resource._statInfo, - source: resource._source - }; - if (resource._stream) { - options.buffer = await resource._getBufferFromStream(); - } - else if (resource._createStream) { - options.createStream = resource._createStream; - } - else if (resource._buffer) { - options.buffer = resource._buffer; - } - return new Resource(options); - } - _assignProjectToResource(resource) { - if (this._project) { - // Assign project to resource if necessary - if (resource.hasProject()) { - if (resource.getProject() !== this._project) { - throw new Error(`Unable to write resource associated with project ` + - `${resource.getProject().getName()} into adapter of project ${this._project.getName()}: ` + - resource.getPath()); - } - return; - } - log.silly(`Associating resource ${resource.getPath()} with project ${this._project.getName()}`); - resource.setProject(this._project); - } - } - _resolveVirtualPathToBase(inputVirPath, writeMode = false) { - if (!path.isAbsolute(inputVirPath)) { - throw new Error(`Failed to resolve virtual path '${inputVirPath}': Path must be absolute`); - } - // Resolve any ".." segments to make sure we compare the effective start of the path - // with the virBasePath - const virPath = path.normalize(inputVirPath); - if (!writeMode) { - // When reading resources, validate against path excludes and return null if the given path - // does not match this adapters base path - if (!this._isPathHandled(virPath)) { - if (log.isLevelEnabled("silly")) { - log.silly(`Failed to resolve virtual path '${inputVirPath}': ` + - `Resolved path does not start with adapter base path '${this._virBasePath}' or equals ` + - `base dir: ${this._virBaseDir}`); - } - return null; - } - if (this._isPathExcluded(virPath)) { - if (log.isLevelEnabled("silly")) { - log.silly(`Failed to resolve virtual path '${inputVirPath}': ` + - `Resolved path is excluded by configuration of adapter with base path '${this._virBasePath}'`); - } - return null; - } - } - else if (!this._isPathHandled(virPath)) { - // Resolved path is not within the configured base path and does - // not equal the virtual base directory. - // Since we don't want to write resources to foreign locations, we throw an error - throw new Error(`Failed to write resource with virtual path '${inputVirPath}': Path must start with ` + - `the configured virtual base path of the adapter. Base path: '${this._virBasePath}'`); - } - const relPath = virPath.substr(this._virBasePath.length); - return relPath; - } -} -export default AbstractAdapter; -//# sourceMappingURL=AbstractAdapter.js.map \ No newline at end of file diff --git a/lib/adapters/AbstractAdapter.js.map b/lib/adapters/AbstractAdapter.js.map deleted file mode 100644 index f4b005cf..00000000 --- a/lib/adapters/AbstractAdapter.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"AbstractAdapter.js","sourceRoot":"","sources":["../../src/adapters/AbstractAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,iBAAiB,CAAC;AACnC,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,MAAM,GAAG,GAAG,SAAS,CAAC,oCAAoC,CAAC,CAAC;AAC5D,OAAO,EAAC,SAAS,EAAC,MAAM,WAAW,CAAC;AACpC,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,oBAAoB,MAAM,4BAA4B,CAAC;AAC9D,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC;;;;;;;;GAQG;AACH,MAAM,eAAgB,SAAQ,oBAAoB;IACjD;;;;;;;;;OASG;IACH,YAAY,EAAC,WAAW,EAAE,QAAQ,GAAG,EAAE,EAAE,OAAO,EAAC;QAChD,IAAI,GAAG,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;YACpC,MAAM,IAAI,SAAS,CAAC,qCAAqC,CAAC,CAAC;QAC5D,CAAC;QACD,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,WAAW,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC9E,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,wEAAwE,WAAW,GAAG,CAAC,CAAC;QACzG,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACd,6EAA6E,WAAW,GAAG,CAAC,CAAC;QAC/F,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;QACjE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IACzB,CAAC;IACD;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,GAAG,EAAC,KAAK,EAAE,IAAI,EAAC,EAAE,KAAK;QACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC;QAEvC,IAAI,CAAC,CAAC,UAAU,YAAY,KAAK,CAAC,EAAE,CAAC;YACpC,UAAU,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;QAED,iCAAiC;QACjC,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAChE,IAAI,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;QAC5D,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QACtD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,EAAE,CAAC;QACX,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACpB,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;gBAClD,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;oBAChE,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;oBAC5B,OAAO;wBACN,IAAI,CAAC,eAAe,CAAC;4BACpB,QAAQ,EAAE;gCACT,WAAW,EAAE;oCACZ,OAAO,IAAI,CAAC;gCACb,CAAC;6BACD;4BACD,MAAM,EAAE;gCACP,OAAO,EAAE,UAAU;6BACnB;4BACD,IAAI,EAAE,OAAO;yBACb,CAAC;qBACF,CAAC;gBACH,CAAC;YACF,CAAC;QACF,CAAC;QACD,OAAO,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC;IAED;;;;;OAKG;IACH,eAAe,CAAC,OAAO;QACtB,OAAO,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACvD,CAAC;IAED;;;;;;;OAOG;IACH,cAAc,CAAC,OAAO;QACrB,qEAAqE;QACrE,OAAO,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,OAAO,KAAK,IAAI,CAAC,WAAW,CAAC;IAC9E,CAAC;IAED;;;;;;OAMG;IACH,iBAAiB,CAAC,UAAU;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAE/C,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAElD,SAAS,WAAW,CAAC,MAAM;YAC1B,IAAI,CAAC,CAAC;YACN,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;gBAC3B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;oBAC5B,GAAG,CAAC,OAAO,CAAC,0DAA0D,CAAC,CAAC;oBACxE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,sBAAsB;wBAC1C,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;oBACpD,CAAC;oBACD,GAAG,CAAC,OAAO,CAAC,sBAAsB,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;oBACtD,GAAG,CAAC,OAAO,CAAC,qBAAqB,UAAU,EAAE,CAAC,CAAC;oBAC/C,GAAG,CAAC,OAAO,CAAC,+BAA+B,CAAC,IAAI,CAAC,CAAC;oBAClD,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;oBACpB,OAAO,EAAC,GAAG,EAAE,CAAC,EAAE,YAAY,EAAE,IAAI,EAAC,CAAC;gBACrC,CAAC;gBACD,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;gBACtC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;oBAClC,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;wBAC/B,OAAO,IAAI,CAAC;oBACb,CAAC;yBAAM,CAAC;wBACP,SAAS;oBACV,CAAC;gBACF,CAAC;qBAAM,IAAI,QAAQ,KAAK,SAAS,CAAC,QAAQ,EAAE,CAAC;oBAC5C,OAAO,EAAC,GAAG,EAAE,CAAC,EAAC,CAAC;gBACjB,CAAC;qBAAM,CAAC,CAAC,QAAQ;oBAChB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;wBAClC,OAAO,IAAI,CAAC;oBACb,CAAC;yBAAM,CAAC;wBACP,SAAS;oBACV,CAAC;gBACF,CAAC;YACF,CAAC;YACD,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,EAAE,CAAC;gBAC5C,OAAO,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC;YAC1B,CAAC;YACD,OAAO,EAAC,GAAG,EAAE,CAAC,EAAC,CAAC;QACjB,CAAC;QAED,MAAM,WAAW,GAAG,EAAE,CAAC;QACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,KAAK,EAAE,CAAC;gBACX,IAAI,aAAa,CAAC;gBAClB,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;oBACxB,aAAa,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC7D,CAAC;qBAAM,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,iBAAiB;oBAC9C,aAAa,GAAG,EAAE,CAAC,CAAC,WAAW;gBAChC,CAAC;qBAAM,CAAC,CAAC,mCAAmC;oBAC3C,aAAa,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAC3D,IAAI,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;wBACnC,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;oBACzC,CAAC;gBACF,CAAC;gBACD,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;oBACf,aAAa,GAAG,GAAG,GAAG,aAAa,CAAC;gBACrC,CAAC;gBACD,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACjC,CAAC;QACF,CAAC;QACD,OAAO,WAAW,CAAC;IACpB,CAAC;IAED,eAAe,CAAC,UAAU;QACzB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC;QACpC,CAAC;QACD,OAAO,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;IAED,gBAAgB,CAAC,QAAQ;QACxB,oEAAoE;QACpE,mEAAmE;QACnE,kDAAkD;QAElD,2DAA2D;QAC3D,wDAAwD;QACxD,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;YACzB,OAAO,QAAQ,CAAC;QACjB,CAAC;QACD,OAAO,IAAI,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,yBAAyB,CAAC,QAAQ;QACvC,MAAM,OAAO,GAAG;YACf,IAAI,EAAE,QAAQ,CAAC,KAAK;YACpB,QAAQ,EAAE,QAAQ,CAAC,SAAS;YAC5B,MAAM,EAAE,QAAQ,CAAC,OAAO;SACxB,CAAC;QAEF,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACtB,OAAO,CAAC,MAAM,GAAG,MAAM,QAAQ,CAAC,oBAAoB,EAAE,CAAC;QACxD,CAAC;aAAM,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;YACnC,OAAO,CAAC,YAAY,GAAG,QAAQ,CAAC,aAAa,CAAC;QAC/C,CAAC;aAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YAC7B,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC;QACnC,CAAC;QACD,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED,wBAAwB,CAAC,QAAQ;QAChC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,0CAA0C;YAC1C,IAAI,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC;gBAC3B,IAAI,QAAQ,CAAC,UAAU,EAAE,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAC7C,MAAM,IAAI,KAAK,CACd,mDAAmD;wBACnD,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC,OAAO,EAAE,4BAA4B,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI;wBACzF,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;gBACtB,CAAC;gBACD,OAAO;YACR,CAAC;YACD,GAAG,CAAC,KAAK,CAAC,wBAAwB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAChG,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC;IACF,CAAC;IAED,yBAAyB,CAAC,YAAY,EAAE,SAAS,GAAG,KAAK;QACxD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,mCAAmC,YAAY,0BAA0B,CAAC,CAAC;QAC5F,CAAC;QACD,oFAAoF;QACpF,uBAAuB;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAE7C,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,2FAA2F;YAC3F,yCAAyC;YACzC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnC,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;oBACjC,GAAG,CAAC,KAAK,CAAC,mCAAmC,YAAY,KAAK;wBAC7D,wDAAwD,IAAI,CAAC,YAAY,cAAc;wBACvF,aAAa,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;gBACnC,CAAC;gBACD,OAAO,IAAI,CAAC;YACb,CAAC;YACD,IAAI,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnC,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;oBACjC,GAAG,CAAC,KAAK,CAAC,mCAAmC,YAAY,KAAK;wBAC7D,yEAAyE,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;gBACjG,CAAC;gBACD,OAAO,IAAI,CAAC;YACb,CAAC;QACF,CAAC;aAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1C,gEAAgE;YAChE,wCAAwC;YACxC,iFAAiF;YACjF,MAAM,IAAI,KAAK,CACd,+CAA+C,YAAY,0BAA0B;gBACrF,gEAAgE,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACzD,OAAO,OAAO,CAAC;IAChB,CAAC;CACD;AAED,eAAe,eAAe,CAAC"} \ No newline at end of file diff --git a/lib/adapters/FileSystem.js b/lib/adapters/FileSystem.js deleted file mode 100644 index da75473e..00000000 --- a/lib/adapters/FileSystem.js +++ /dev/null @@ -1,345 +0,0 @@ -import { getLogger } from "@ui5/logger"; -const log = getLogger("resources:adapters:FileSystem"); -import path from "node:path"; -import { promisify } from "node:util"; -import fs from "graceful-fs"; -const copyFile = promisify(fs.copyFile); -const chmod = promisify(fs.chmod); -const mkdir = promisify(fs.mkdir); -const stat = promisify(fs.stat); -import { globby, isGitIgnored } from "globby"; -import { PassThrough } from "node:stream"; -import AbstractAdapter from "./AbstractAdapter.js"; -const READ_ONLY_MODE = 0o444; -const ADAPTER_NAME = "FileSystem"; -/** - * File system resource adapter - * - * @public - * @class - * @alias @ui5/fs/adapters/FileSystem - * @extends @ui5/fs/adapters/AbstractAdapter - */ -class FileSystem extends AbstractAdapter { - /** - * The Constructor. - * - * @param {object} parameters Parameters - * @param {string} parameters.virBasePath - * Virtual base path. Must be absolute, POSIX-style, and must end with a slash - * @param {string} parameters.fsBasePath - * File System base path. Must be absolute and must use platform-specific path segment separators - * @param {string[]} [parameters.excludes] List of glob patterns to exclude - * @param {object} [parameters.useGitignore=false] - * Whether to apply any excludes defined in an optional .gitignore in the given fsBasePath directory - * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) - */ - constructor({ virBasePath, project, fsBasePath, excludes, useGitignore = false }) { - super({ virBasePath, project, excludes }); - if (!fsBasePath) { - throw new Error(`Unable to create adapter: Missing parameter 'fsBasePath'`); - } - // Ensure path is resolved to an absolute path, ending with a slash (or backslash on Windows) - // path.resolve will always remove any trailing segment separator - this._fsBasePath = path.join(path.resolve(fsBasePath), path.sep); - this._useGitignore = !!useGitignore; - } - /** - * Locate resources by glob. - * - * @private - * @param {Array} patterns Array of glob patterns - * @param {object} [options={}] glob options - * @param {boolean} [options.nodir=true] Do not match directories - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources - */ - async _runGlob(patterns, options = { nodir: true }, trace) { - const opt = { - cwd: this._fsBasePath, - dot: true, - onlyFiles: options.nodir, - followSymbolicLinks: false, - gitignore: this._useGitignore, - }; - trace.globCall(); - const promises = []; - if (!opt.onlyFiles && patterns.includes("")) { // Match physical root directory - promises.push(new Promise((resolve, reject) => { - fs.stat(this._fsBasePath, (err, stat) => { - if (err) { - reject(err); - } - else { - resolve(this._createResource({ - project: this._project, - statInfo: stat, - path: this._virBaseDir, - sourceMetadata: { - adapter: ADAPTER_NAME, - fsPath: this._fsBasePath - }, - createStream: () => { - return fs.createReadStream(this._fsBasePath); - } - })); - } - }); - })); - } - // Remove empty string glob patterns - // Starting with globby v8 or v9 empty glob patterns "" act like "**" - // Micromatch throws on empty strings. We just ignore them since they are - // typically caused by our normalization in the AbstractAdapter - const globbyPatterns = patterns.filter((pattern) => { - return pattern !== ""; - }); - if (globbyPatterns.length > 0) { - const matches = await globby(globbyPatterns, opt); - for (let i = matches.length - 1; i >= 0; i--) { - promises.push(new Promise((resolve, reject) => { - const virPath = (this._virBasePath + matches[i]); - const relPath = this._resolveVirtualPathToBase(virPath); - if (relPath === null) { - // Match is likely outside adapter base path - log.verbose(`Failed to resolve virtual path of glob match '${virPath}': Path must start with ` + - `the configured virtual base path of the adapter. Base path: '${this._virBasePath}'`); - resolve(null); - } - const fsPath = this._resolveToFileSystem(relPath); - // Workaround for not getting the stat from the glob - fs.stat(fsPath, (err, stat) => { - if (err) { - reject(err); - } - else { - resolve(this._createResource({ - project: this._project, - statInfo: stat, - path: virPath, - sourceMetadata: { - adapter: ADAPTER_NAME, - fsPath: fsPath - }, - createStream: () => { - return fs.createReadStream(fsPath); - } - })); - } - }); - })); - } - } - const results = await Promise.all(promises); - // Flatten results - return Array.prototype.concat.apply([], results).filter(($) => $); - } - /** - * Locate a resource by path. - * - * @private - * @param {string} virPath Absolute virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource or null if not found - */ - async _byPath(virPath, options, trace) { - const relPath = this._resolveVirtualPathToBase(virPath); - if (relPath === null) { - // Neither starts with basePath, nor equals baseDirectory - if (!options.nodir && this._virBasePath.startsWith(virPath)) { - // Create virtual directories for the virtual base path (which has to exist) - // TODO: Maybe improve this by actually matching the base paths segments to the virPath - return this._createResource({ - project: this._project, - statInfo: { - isDirectory: function () { - return true; - } - }, - path: virPath - }); - } - else { - return null; - } - } - const fsPath = this._resolveToFileSystem(relPath); - trace.pathCall(); - if (this._useGitignore) { - if (!this._isGitIgnored) { - this._isGitIgnored = await isGitIgnored({ - cwd: this._fsBasePath - }); - } - // Check whether path should be ignored - if (this._isGitIgnored(fsPath)) { - // Path is ignored by .gitignore - return null; - } - } - try { - const statInfo = await stat(fsPath); - if (options.nodir && statInfo.isDirectory()) { - return null; - } - const resourceOptions = { - project: this._project, - statInfo, - path: virPath, - sourceMetadata: { - adapter: ADAPTER_NAME, - fsPath - } - }; - if (!statInfo.isDirectory()) { - // Add content as lazy stream - resourceOptions.createStream = function () { - return fs.createReadStream(fsPath); - }; - } - return this._createResource(resourceOptions); - } - catch (err) { - if (err.code === "ENOENT") { // "File or directory does not exist" - return null; - } - else { - throw err; - } - } - } - /** - * Writes the content of a resource to a path. - * - * @private - * @param {@ui5/fs/Resource} resource Resource to write - * @param {object} [options] - * @param {boolean} [options.readOnly] Whether the resource content shall be written read-only - * Do not use in conjunction with the drain option. - * The written file will be used as the new source of this resources content. - * Therefore the written file should not be altered by any means. - * Activating this option might improve overall memory consumption. - * @param {boolean} [options.drain] Whether the resource content shall be emptied during the write process. - * Do not use in conjunction with the readOnly option. - * Activating this option might improve overall memory consumption. - * This should be used in cases where this is the last access to the resource. - * E.g. the final write of a resource after all processing is finished. - * @returns {Promise} Promise resolving once data has been written - */ - async _write(resource, { drain, readOnly }) { - resource = this._migrateResource(resource); - if (resource instanceof Promise) { - // Only await if the migrate function returned a promise - // Otherwise await would automatically create a Promise, causing unwanted overhead - resource = await resource; - } - this._assignProjectToResource(resource); - if (drain && readOnly) { - throw new Error(`Error while writing resource ${resource.getPath()}: ` + - "Do not use options 'drain' and 'readOnly' at the same time."); - } - const relPath = this._resolveVirtualPathToBase(resource.getPath(), true); - const fsPath = this._resolveToFileSystem(relPath); - const dirPath = path.dirname(fsPath); - await mkdir(dirPath, { recursive: true }); - const sourceMetadata = resource.getSourceMetadata(); - if (sourceMetadata && sourceMetadata.adapter === ADAPTER_NAME && sourceMetadata.fsPath) { - // Resource has been created by FileSystem adapter. This means it might require special handling - /* The following code covers these four conditions: - 1. FS-paths not equal + Resource not modified => Shortcut: Use fs.copyFile - 2. FS-paths equal + Resource not modified => Shortcut: Skip write altogether - 3. FS-paths equal + Resource modified => Drain stream into buffer. Later write from buffer as usual - 4. FS-paths not equal + Resource modified => No special handling. Write from stream or buffer - */ - if (sourceMetadata.fsPath !== fsPath && !sourceMetadata.contentModified) { - // Shortcut: fs.copyFile can be used when the resource hasn't been modified - log.silly(`Resource hasn't been modified. Copying resource from ${sourceMetadata.fsPath} to ${fsPath}`); - await copyFile(sourceMetadata.fsPath, fsPath); - if (readOnly) { - await chmod(fsPath, READ_ONLY_MODE); - } - return; - } - else if (sourceMetadata.fsPath === fsPath && !sourceMetadata.contentModified) { - log.silly(`Resource hasn't been modified, target path equals source path. Skipping write to ${fsPath}`); - if (readOnly) { - await chmod(fsPath, READ_ONLY_MODE); - } - return; - } - else if (sourceMetadata.fsPath === fsPath && sourceMetadata.contentModified) { - // Resource has been modified. Make sure all streams are drained to prevent - // issues caused by piping the original read-stream into a write-stream for the same path - await resource.getBuffer(); - } - else { /* Different paths + modifications require no special handling */ } - } - log.silly(`Writing to ${fsPath}`); - await new Promise((resolve, reject) => { - let contentStream; - if (drain || readOnly) { - // Stream will be drained - contentStream = resource.getStream(); - contentStream.on("error", (err) => { - reject(err); - }); - } - else { - // Transform stream into buffer before writing - contentStream = new PassThrough(); - const buffers = []; - contentStream.on("error", (err) => { - reject(err); - }); - contentStream.on("data", (data) => { - buffers.push(data); - }); - contentStream.on("end", () => { - const buffer = Buffer.concat(buffers); - resource.setBuffer(buffer); - }); - resource.getStream().pipe(contentStream); - } - const writeOptions = {}; - if (readOnly) { - writeOptions.mode = READ_ONLY_MODE; - } - const write = fs.createWriteStream(fsPath, writeOptions); - write.on("error", (err) => { - reject(err); - }); - write.on("close", (ex) => { - resolve(); - }); - contentStream.pipe(write); - }); - if (readOnly) { - if (sourceMetadata?.fsPath === fsPath) { - // When streaming into the same file, permissions need to be changed explicitly - await chmod(fsPath, READ_ONLY_MODE); - } - // In case of readOnly, we drained the stream and can now set a new callback - // for creating a stream from written file - // This should be identical to buffering the resource content in memory, since the written file - // can not be modified. - // We chose this approach to be more memory efficient in scenarios where readOnly is used - resource.setStream(function () { - return fs.createReadStream(fsPath); - }); - } - } - _resolveToFileSystem(relPath) { - const fsPath = path.join(this._fsBasePath, relPath); - if (!fsPath.startsWith(this._fsBasePath)) { - log.verbose(`Failed to resolve virtual path internally: ${relPath}`); - log.verbose(` Adapter base path: ${this._fsBasePath}`); - log.verbose(` Resulting path: ${fsPath}`); - throw new Error(`Error while resolving internal virtual path: '${relPath}' resolves ` + - `to a directory not accessible by this File System adapter instance`); - } - return fsPath; - } -} -export default FileSystem; -//# sourceMappingURL=FileSystem.js.map \ No newline at end of file diff --git a/lib/adapters/FileSystem.js.map b/lib/adapters/FileSystem.js.map deleted file mode 100644 index 0487c629..00000000 --- a/lib/adapters/FileSystem.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"FileSystem.js","sourceRoot":"","sources":["../../src/adapters/FileSystem.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/adapters/Memory.js b/lib/adapters/Memory.js deleted file mode 100644 index e2f31208..00000000 --- a/lib/adapters/Memory.js +++ /dev/null @@ -1,162 +0,0 @@ -import { getLogger } from "@ui5/logger"; -const log = getLogger("resources:adapters:Memory"); -import micromatch from "micromatch"; -import AbstractAdapter from "./AbstractAdapter.js"; -const ADAPTER_NAME = "Memory"; -/** - * Virtual resource Adapter - * - * @public - * @class - * @alias @ui5/fs/adapters/Memory - * @extends @ui5/fs/adapters/AbstractAdapter - */ -class Memory extends AbstractAdapter { - /** - * The constructor. - * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.virBasePath - * Virtual base path. Must be absolute, POSIX-style, and must end with a slash - * @param {string[]} [parameters.excludes] List of glob patterns to exclude - * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) - */ - constructor({ virBasePath, project, excludes }) { - super({ virBasePath, project, excludes }); - this._virFiles = Object.create(null); // map full of files - this._virDirs = Object.create(null); // map full of directories - } - /** - * Matches and returns resources from a given map (either _virFiles or _virDirs). - * - * @private - * @param {string[]} patterns - * @param {object} resourceMap - * @returns {Promise} - */ - async _matchPatterns(patterns, resourceMap) { - const resourcePaths = Object.keys(resourceMap); - const matchedPaths = micromatch(resourcePaths, patterns, { - dot: true - }); - return await Promise.all(matchedPaths.map((virPath) => { - const resource = resourceMap[virPath]; - if (resource) { - return this._cloneResource(resource); - } - })); - } - async _cloneResource(resource) { - const clonedResource = await resource.clone(); - if (this._project) { - clonedResource.setProject(this._project); - } - return clonedResource; - } - /** - * Locate resources by glob. - * - * @private - * @param {Array} patterns array of glob patterns - * @param {object} [options={}] glob options - * @param {boolean} [options.nodir=true] Do not match directories - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources - */ - async _runGlob(patterns, options = { nodir: true }, trace) { - if (patterns[0] === "" && !options.nodir) { // Match virtual root directory - return [ - this._createResource({ - project: this._project, - statInfo: { - isDirectory: function () { - return true; - } - }, - sourceMetadata: { - adapter: ADAPTER_NAME - }, - path: this._virBasePath.slice(0, -1) - }) - ]; - } - let matchedResources = await this._matchPatterns(patterns, this._virFiles); - if (!options.nodir) { - const matchedDirs = await this._matchPatterns(patterns, this._virDirs); - matchedResources = matchedResources.concat(matchedDirs); - } - return matchedResources; - } - /** - * Locates resources by path. - * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource - */ - async _byPath(virPath, options, trace) { - const relPath = this._resolveVirtualPathToBase(virPath); - if (relPath === null) { - return null; - } - trace.pathCall(); - const resource = this._virFiles[relPath]; - if (!resource || (options.nodir && resource.getStatInfo().isDirectory())) { - return null; - } - else { - return await this._cloneResource(resource); - } - } - /** - * Writes the content of a resource to a path. - * - * @private - * @param {@ui5/fs/Resource} resource The Resource to write - * @returns {Promise} Promise resolving once data has been written - */ - async _write(resource) { - resource = this._migrateResource(resource); - if (resource instanceof Promise) { - // Only await if the migrate function returned a promise - // Otherwise await would automatically create a Promise, causing unwanted overhead - resource = await resource; - } - this._assignProjectToResource(resource); - const relPath = this._resolveVirtualPathToBase(resource.getPath(), true); - log.silly(`Writing to virtual path ${resource.getPath()}`); - this._virFiles[relPath] = await resource.clone(); - // Add virtual directories for all path segments of the written resource - // TODO: Add tests for all this - const pathSegments = relPath.split("/"); - pathSegments.pop(); // Remove last segment representing the resource itself - pathSegments.forEach((segment, i) => { - if (i >= 1) { - segment = pathSegments[i - 1] + "/" + segment; - } - pathSegments[i] = segment; - }); - for (let i = pathSegments.length - 1; i >= 0; i--) { - const segment = pathSegments[i]; - if (!this._virDirs[segment]) { - this._virDirs[segment] = this._createResource({ - project: this._project, - sourceMetadata: { - adapter: ADAPTER_NAME - }, - statInfo: { - isDirectory: function () { - return true; - } - }, - path: this._virBasePath + segment - }); - } - } - } -} -export default Memory; -//# sourceMappingURL=Memory.js.map \ No newline at end of file diff --git a/lib/adapters/Memory.js.map b/lib/adapters/Memory.js.map deleted file mode 100644 index 18b95875..00000000 --- a/lib/adapters/Memory.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Memory.js","sourceRoot":"","sources":["../../src/adapters/Memory.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/fsInterface.js b/lib/fsInterface.js deleted file mode 100644 index d3af8b5e..00000000 --- a/lib/fsInterface.js +++ /dev/null @@ -1,90 +0,0 @@ -function toPosix(inputPath) { - return inputPath.replace(/\\/g, "/"); -} -/** - * @public - * @module @ui5/fs/fsInterface - */ -/** - * Wraps readers to access them through a [Node.js fs]{@link https://nodejs.org/api/fs.html} styled interface. - * - * @public - * @function default - * @static - * @param {@ui5/fs/AbstractReader} reader Resource Reader or Collection - * - * @returns {object} Object with [Node.js fs]{@link https://nodejs.org/api/fs.html} styled functions - * [readFile]{@link https://nodejs.org/api/fs.html#fs_fs_readfile_path_options_callback}, - * [stat]{@link https://nodejs.org/api/fs.html#fs_fs_stat_path_options_callback}, - * [readdir]{@link https://nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback} and - * [mkdir]{@link https://nodejs.org/api/fs.html#fs_fs_mkdir_path_options_callback} - */ -function fsInterface(reader) { - return { - readFile(fsPath, options, callback) { - if (typeof options === "function") { - callback = options; - options = undefined; - } - if (typeof options === "string") { - options = { encoding: options }; - } - const posixPath = toPosix(fsPath); - reader.byPath(posixPath, { - nodir: false - }).then(function (resource) { - if (!resource) { - const error = new Error(`ENOENT: no such file or directory, open '${fsPath}'`); - error.code = "ENOENT"; // "File or directory does not exist" - callback(error); - return; - } - return resource.getBuffer().then(function (buffer) { - let res; - if (options && options.encoding) { - res = buffer.toString(options.encoding); - } - else { - res = buffer; - } - callback(null, res); - }); - }).catch(callback); - }, - stat(fsPath, callback) { - const posixPath = toPosix(fsPath); - reader.byPath(posixPath, { - nodir: false - }).then(function (resource) { - if (!resource) { - const error = new Error(`ENOENT: no such file or directory, stat '${fsPath}'`); - error.code = "ENOENT"; // "File or directory does not exist" - callback(error); - } - else { - callback(null, resource.getStatInfo()); - } - }).catch(callback); - }, - readdir(fsPath, callback) { - let posixPath = toPosix(fsPath); - if (!posixPath.match(/\/$/)) { - // Add trailing slash if not present - posixPath += "/"; - } - reader.byGlob(posixPath + "*", { - nodir: false - }).then((resources) => { - const files = resources.map((resource) => { - return resource.getName(); - }); - callback(null, files); - }).catch(callback); - }, - mkdir(fsPath, callback) { - setTimeout(callback, 0); - } - }; -} -export default fsInterface; -//# sourceMappingURL=fsInterface.js.map \ No newline at end of file diff --git a/lib/fsInterface.js.map b/lib/fsInterface.js.map deleted file mode 100644 index 1c3919ca..00000000 --- a/lib/fsInterface.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"fsInterface.js","sourceRoot":"","sources":["../src/fsInterface.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/readers/Filter.js b/lib/readers/Filter.js deleted file mode 100644 index 0a8abc3b..00000000 --- a/lib/readers/Filter.js +++ /dev/null @@ -1,71 +0,0 @@ -import AbstractReader from "../AbstractReader.js"; -/** - * A reader that allows dynamic filtering of resources passed through it - * - * @public - * @class - * @alias @ui5/fs/readers/Filter - * @extends @ui5/fs/AbstractReader - */ -class Filter extends AbstractReader { - /** - * Filter callback - * - * @public - * @callback @ui5/fs/readers/Filter~callback - * @param {@ui5/fs/Resource} resource Resource to test - * @returns {boolean} Whether to keep the resource - */ - /** - * Constructor - * - * @public - * @param {object} parameters Parameters - * @param {@ui5/fs/AbstractReader} parameters.reader The resource reader or collection to wrap - * @param {@ui5/fs/readers/Filter~callback} parameters.callback - * Filter function. Will be called for every resource read through this reader. - */ - constructor({ reader, callback }) { - super(); - if (!reader) { - throw new Error(`Missing parameter "reader"`); - } - if (!callback) { - throw new Error(`Missing parameter "callback"`); - } - this._reader = reader; - this._callback = callback; - } - /** - * Locates resources by glob. - * - * @private - * @param {string|string[]} pattern glob pattern as string or an array of - * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing/Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources - */ - async _byGlob(pattern, options, trace) { - const result = await this._reader._byGlob(pattern, options, trace); - return result.filter(this._callback); - } - /** - * Locates resources by path. - * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing/Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource - */ - async _byPath(virPath, options, trace) { - const result = await this._reader._byPath(virPath, options, trace); - if (result && !this._callback(result)) { - return null; - } - return result; - } -} -export default Filter; -//# sourceMappingURL=Filter.js.map \ No newline at end of file diff --git a/lib/readers/Filter.js.map b/lib/readers/Filter.js.map deleted file mode 100644 index b9e1ba6c..00000000 --- a/lib/readers/Filter.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Filter.js","sourceRoot":"","sources":["../../src/readers/Filter.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,MAAO,SAAQ,cAAc;IAClC;;;;;;;MAOE;IAEF;;;;;;;;OAQG;IACH,YAAY,EAAC,MAAM,EAAE,QAAQ,EAAC;QAC7B,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACjD,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QACpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QACnE,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK;QACpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QACnE,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC;CACD;AAED,eAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/readers/Link.js b/lib/readers/Link.js deleted file mode 100644 index 2487941e..00000000 --- a/lib/readers/Link.js +++ /dev/null @@ -1,131 +0,0 @@ -import AbstractReader from "../AbstractReader.js"; -import ResourceFacade from "../ResourceFacade.js"; -import { prefixGlobPattern } from "../resourceFactory.js"; -import { getLogger } from "@ui5/logger"; -const log = getLogger("resources:readers:Link"); -/** - * A reader that allows for rewriting paths segments of all resources passed through it. - * - * @example - * import Link from "@ui5/fs/readers/Link"; - * const linkedReader = new Link({ - * reader: sourceReader, - * pathMapping: { - * linkPath: `/app`, - * targetPath: `/resources/my-app-name/` - * } - * }); - * - * // The following resolves with a @ui5/fs/ResourceFacade of the resource - * // located at "/resources/my-app-name/Component.js" in the sourceReader - * const resource = await linkedReader.byPath("/app/Component.js"); - * - * @public - * @class - * @alias @ui5/fs/readers/Link - * @extends @ui5/fs/AbstractReader - */ -class Link extends AbstractReader { - /** - * Path mapping for a [Link]{@link @ui5/fs/readers/Link} - * - * @public - * @typedef {object} @ui5/fs/readers/Link/PathMapping - * @property {string} linkPath Path to match and replace in the requested path or pattern - * @property {string} targetPath Path to use as a replacement in the request for the source reader - */ - /** - * Constructor - * - * @public - * @param {object} parameters Parameters - * @param {@ui5/fs/AbstractReader} parameters.reader The resource reader or collection to wrap - * @param {@ui5/fs/readers/Link/PathMapping} parameters.pathMapping - */ - constructor({ reader, pathMapping }) { - super(); - if (!reader) { - throw new Error(`Missing parameter "reader"`); - } - if (!pathMapping) { - throw new Error(`Missing parameter "pathMapping"`); - } - this._reader = reader; - this._pathMapping = pathMapping; - Link._validatePathMapping(pathMapping); - } - /** - * Locates resources by glob. - * - * @private - * @param {string|string[]} patterns glob pattern as string or an array of - * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing/Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources - */ - async _byGlob(patterns, options, trace) { - if (!(patterns instanceof Array)) { - patterns = [patterns]; - } - patterns = patterns.map((pattern) => { - if (pattern.startsWith(this._pathMapping.linkPath)) { - pattern = pattern.substr(this._pathMapping.linkPath.length); - } - return prefixGlobPattern(pattern, this._pathMapping.targetPath); - }); - // Flatten prefixed patterns - patterns = Array.prototype.concat.apply([], patterns); - // Keep resource's internal path unchanged for now - const resources = await this._reader._byGlob(patterns, options, trace); - return resources.map((resource) => { - const resourcePath = resource.getPath(); - if (resourcePath.startsWith(this._pathMapping.targetPath)) { - return new ResourceFacade({ - resource, - path: this._pathMapping.linkPath + resourcePath.substr(this._pathMapping.targetPath.length) - }); - } - }); - } - /** - * Locates resources by path. - * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing/Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource - */ - async _byPath(virPath, options, trace) { - if (!virPath.startsWith(this._pathMapping.linkPath)) { - return null; - } - const targetPath = this._pathMapping.targetPath + virPath.substr(this._pathMapping.linkPath.length); - log.silly(`byPath: Rewriting virtual path ${virPath} to ${targetPath}`); - const resource = await this._reader._byPath(targetPath, options, trace); - if (resource) { - return new ResourceFacade({ - resource, - path: this._pathMapping.linkPath + resource.getPath().substr(this._pathMapping.targetPath.length) - }); - } - return null; - } - static _validatePathMapping({ linkPath, targetPath }) { - if (!linkPath) { - throw new Error(`Path mapping is missing attribute "linkPath"`); - } - if (!targetPath) { - throw new Error(`Path mapping is missing attribute "targetPath"`); - } - if (!linkPath.endsWith("/")) { - throw new Error(`Link path must end with a slash: ${linkPath}`); - } - if (!targetPath.endsWith("/")) { - throw new Error(`Target path must end with a slash: ${targetPath}`); - } - } -} -export default Link; -//# sourceMappingURL=Link.js.map \ No newline at end of file diff --git a/lib/readers/Link.js.map b/lib/readers/Link.js.map deleted file mode 100644 index 2d55add0..00000000 --- a/lib/readers/Link.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Link.js","sourceRoot":"","sources":["../../src/readers/Link.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/resourceFactory.js b/lib/resourceFactory.js deleted file mode 100644 index 3018ebe1..00000000 --- a/lib/resourceFactory.js +++ /dev/null @@ -1,266 +0,0 @@ -import path from "node:path"; -import { minimatch } from "minimatch"; -import DuplexCollection from "./DuplexCollection.js"; -import FsAdapter from "./adapters/FileSystem.js"; -import MemAdapter from "./adapters/Memory.js"; -import ReaderCollection from "./ReaderCollection.js"; -import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; -import Resource from "./Resource.js"; -import WriterCollection from "./WriterCollection.js"; -import Filter from "./readers/Filter.js"; -import Link from "./readers/Link.js"; -import { getLogger } from "@ui5/logger"; -const log = getLogger("resources:resourceFactory"); -/** - * @module @ui5/fs/resourceFactory - * @description A collection of resource related APIs - * @public - */ -/** - * Creates a resource ReaderWriter. - * - * If a file system base path is given, file system resource ReaderWriter is returned. - * In any other case a virtual one. - * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.virBasePath Virtual base path. Must be absolute, POSIX-style, and must end with a slash - * @param {string} [parameters.fsBasePath] - * File System base path. - * If this parameter is supplied, a File System adapter will be created instead of a Memory adapter. - * The provided path must be absolute and must use platform-specific path segment separators. - * @param {string[]} [parameters.excludes] List of glob patterns to exclude - * @param {object} [parameters.useGitignore=false] - * Whether to apply any excludes defined in an optional .gitignore in the base directory. - * This parameter only takes effect in conjunction with the fsBasePath parameter. - * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) - * @returns {@ui5/fs/adapters/FileSystem|@ui5/fs/adapters/Memory} File System- or Virtual Adapter - */ -export function createAdapter({ fsBasePath, virBasePath, project, excludes, useGitignore }) { - if (fsBasePath) { - return new FsAdapter({ fsBasePath, virBasePath, project, excludes, useGitignore }); - } - else { - return new MemAdapter({ virBasePath, project, excludes }); - } -} -/** - * Creates a File System adapter and wraps it in a ReaderCollection - * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.virBasePath Virtual base path. Must be absolute, POSIX-style, and must end with a slash - * @param {string} parameters.fsBasePath - * File System base path. Must be absolute and must use platform-specific path segment separators - * @param {object} [parameters.project] Experimental, internal parameter. Do not use - * @param {string[]} [parameters.excludes] List of glob patterns to exclude - * @param {string} [parameters.name] Name for the reader collection - * @returns {@ui5/fs/ReaderCollection} Reader collection wrapping an adapter - */ -export function createReader({ fsBasePath, virBasePath, project, excludes = [], name }) { - if (!fsBasePath) { - // Creating a reader with a memory adapter seems pointless right now - // since there would be no way to fill the adapter with resources - throw new Error(`Unable to create reader: Missing parameter "fsBasePath"`); - } - let normalizedExcludes = excludes; - // If a project is supplied, and that project is of type application, - // Prefix all exclude patterns with the virtual base path (unless it already starts with that) - // TODO 4.0: // TODO specVersion 4.0: Disallow excludes without namespaced prefix in configuration - // Specifying an exclude for "/test" is disambigous as it neither reflects the source path nor the - // ui5 runtime path of the excluded resources. Therefore, only allow paths like /resources//test - // starting with specVersion 4.0 - if (excludes.length && project && project.getType() === "application") { - normalizedExcludes = excludes.map((pattern) => { - if (pattern.startsWith(virBasePath) || pattern.startsWith("!" + virBasePath)) { - return pattern; - } - log.verbose(`Prefixing exclude pattern defined in application project ${project.getName()}: ${pattern}`); - return prefixGlobPattern(pattern, virBasePath); - }); - // Flatten list of patterns - normalizedExcludes = Array.prototype.concat.apply([], normalizedExcludes); - log.verbose(`Effective exclude patterns for application project ${project.getName()}:\n` + - normalizedExcludes.join(", ")); - } - return new ReaderCollection({ - name, - readers: [createAdapter({ - fsBasePath, - virBasePath, - project, - excludes: normalizedExcludes - })] - }); -} -/** - * Creates a ReaderCollection - * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.name The collection name - * @param {@ui5/fs/AbstractReader[]} parameters.readers List of resource readers (all tried in parallel) - * @returns {@ui5/fs/ReaderCollection} Reader collection wrapping provided readers - */ -export function createReaderCollection({ name, readers }) { - return new ReaderCollection({ - name, - readers - }); -} -/** - * Creates a ReaderCollectionPrioritized - * - * @public - * @param {object} parameters - * @param {string} parameters.name The collection name - * @param {@ui5/fs/AbstractReader[]} parameters.readers Prioritized list of resource readers - * (first is tried first) - * @returns {@ui5/fs/ReaderCollectionPrioritized} Reader collection wrapping provided readers - */ -export function createReaderCollectionPrioritized({ name, readers }) { - return new ReaderCollectionPrioritized({ - name, - readers - }); -} -/** - * Creates a WriterCollection - * - * @public - * @param {object} parameters - * @param {string} parameters.name The collection name - * @param {object.} parameters.writerMapping Mapping of virtual base - * paths to writers. Path are matched greedy - * @returns {@ui5/fs/WriterCollection} Writer collection wrapping provided writers - */ -export function createWriterCollection({ name, writerMapping }) { - return new WriterCollection({ - name, - writerMapping - }); -} -/** - * Creates a [Resource]{@link @ui5/fs/Resource}. - * Accepts the same parameters as the [Resource]{@link @ui5/fs/Resource} constructor. - * - * @public - * @param {object} parameters Parameters to be passed to the resource constructor - * @returns {@ui5/fs/Resource} Resource - */ -export function createResource(parameters) { - return new Resource(parameters); -} -/** - * Creates a Workspace - * - * A workspace is a DuplexCollection which reads from the project sources. It is used during the build process - * to write modified files into a separate writer, this is usually a Memory adapter. If a file already exists it is - * fetched from the memory to work on it in further build steps. - * - * @public - * @param {object} parameters - * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers - * @param {@ui5/fs/AbstractReaderWriter} [parameters.writer] A ReaderWriter instance which is - * only used for writing files. If not supplied, a Memory adapter will be created. - * @param {string} [parameters.name="workspace"] Name of the collection - * @param {string} [parameters.virBasePath="/"] Virtual base path - * @returns {@ui5/fs/DuplexCollection} DuplexCollection which wraps the provided resource locators - */ -export function createWorkspace({ reader, writer, virBasePath = "/", name = "workspace" }) { - if (!writer) { - writer = new MemAdapter({ - virBasePath - }); - } - return new DuplexCollection({ - reader, - writer, - name - }); -} -/** - * Create a [Filter-Reader]{@link @ui5/fs/readers/Filter} with the given reader. - * The provided callback is called for every resource that is retrieved through the - * reader and decides whether the resource shall be passed on or dropped. - * - * @public - * @param {object} parameters - * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers - * @param {@ui5/fs/readers/Filter~callback} parameters.callback - * Filter function. Will be called for every resource passed through this reader. - * @returns {@ui5/fs/readers/Filter} Reader instance - */ -export function createFilterReader(parameters) { - return new Filter(parameters); -} -/** - * Create a [Link-Reader]{@link @ui5/fs/readers/Filter} with the given reader. - * The provided path mapping allows for rewriting paths segments of all resources passed through it. - * - * @example - * import {createLinkReader} from "@ui5/fs/resourceFactory"; - * const linkedReader = createLinkReader({ - * reader: sourceReader, - * pathMapping: { - * linkPath: `/app`, - * targetPath: `/resources/my-app-name/` - * } - * }); - * - * // The following resolves with a @ui5/fs/ResourceFacade of the resource - * // located at "/resources/my-app-name/Component.js" in the sourceReader - * const resource = await linkedReader.byPath("/app/Component.js"); - * - * @public - * @param {object} parameters - * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers - * @param {@ui5/fs/readers/Link/PathMapping} parameters.pathMapping - * @returns {@ui5/fs/readers/Link} Reader instance - */ -export function createLinkReader(parameters) { - return new Link(parameters); -} -/** - * Create a [Link-Reader]{@link @ui5/fs/readers/Link} where all requests are prefixed with - * /resources/. - * - * This simulates "flat" resource access, which is for example common for projects of type - * "application". - * - * @public - * @param {object} parameters - * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers - * @param {string} parameters.namespace Project namespace - * @returns {@ui5/fs/readers/Link} Reader instance - */ -export function createFlatReader({ reader, namespace }) { - return new Link({ - reader: reader, - pathMapping: { - linkPath: `/`, - targetPath: `/resources/${namespace}/` - } - }); -} -/** - * Normalizes virtual glob patterns by prefixing them with - * a given virtual base directory path - * - * @param {string} virPattern glob pattern for virtual directory structure - * @param {string} virBaseDir virtual base directory path to prefix the given patterns with - * @returns {string[]} A list of normalized glob patterns - */ -export function prefixGlobPattern(virPattern, virBaseDir) { - const mm = new minimatch.Minimatch(virPattern); - const resultGlobs = []; - for (let i = 0; i < mm.globSet.length; i++) { - let resultPattern = path.posix.join(virBaseDir, mm.globSet[i]); - if (mm.negate) { - resultPattern = "!" + resultPattern; - } - resultGlobs.push(resultPattern); - } - return resultGlobs; -} -//# sourceMappingURL=resourceFactory.js.map \ No newline at end of file diff --git a/lib/resourceFactory.js.map b/lib/resourceFactory.js.map deleted file mode 100644 index 9a3d430a..00000000 --- a/lib/resourceFactory.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"resourceFactory.js","sourceRoot":"","sources":["../src/resourceFactory.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/tracing/Trace.js b/lib/tracing/Trace.js deleted file mode 100644 index 2b48e295..00000000 --- a/lib/tracing/Trace.js +++ /dev/null @@ -1,91 +0,0 @@ -import { getLogger } from "@ui5/logger"; -const log = getLogger("resources:tracing:Trace"); -const logGlobs = getLogger("resources:tracing:Trace:globs"); -const logPaths = getLogger("resources:tracing:Trace:paths"); -import prettyHrtime from "pretty-hrtime"; -import summaryTrace from "./traceSummary.js"; -const hasOwnProperty = Object.prototype.hasOwnProperty; -/** - * Trace - * - * @private - * @class - */ -class Trace { - constructor(name) { - if (!log.isLevelEnabled("silly")) { - return; - } - this._name = name; - this._startTime = process.hrtime(); - this._globCalls = 0; - this._pathCalls = 0; - this._collections = Object.create(null); - summaryTrace.traceStarted(); - } - globCall() { - if (!log.isLevelEnabled("silly")) { - return; - } - this._globCalls++; - summaryTrace.globCall(); - } - pathCall() { - if (!log.isLevelEnabled("silly")) { - return; - } - this._pathCalls++; - summaryTrace.pathCall(); - } - collection(name) { - if (!log.isLevelEnabled("silly")) { - return; - } - const collection = this._collections[name]; - if (collection) { - this._collections[name].calls++; - } - else { - this._collections[name] = { - calls: 1 - }; - } - summaryTrace.collection(name); - } - printReport() { - if (!log.isLevelEnabled("silly")) { - return; - } - let report = ""; - const timeDiff = process.hrtime(this._startTime); - const time = prettyHrtime(timeDiff); - const colCount = Object.keys(this._collections).length; - report += `[Trace: ${this._name}\n`; - report += ` ${time} elapsed time \n`; - if (this._globCalls) { - report += ` ${this._globCalls} glob executions\n`; - } - if (this._pathCalls) { - report += ` ${this._pathCalls} path stats\n`; - } - report += ` ${colCount} reader-collections involed:\n`; - for (const coll in this._collections) { - if (hasOwnProperty.call(this._collections, coll)) { - report += ` ${this._collections[coll].calls}x ${coll}\n`; - } - } - report += "======================]"; - if (this._globCalls && this._pathCalls) { - log.silly(report); - } - else if (this._globCalls) { - logGlobs.silly(report); - } - else { - logPaths.silly(report); - } - summaryTrace.traceEnded(); - } -} -export default Trace; -//# sourceMappingURL=Trace.js.map \ No newline at end of file diff --git a/lib/tracing/Trace.js.map b/lib/tracing/Trace.js.map deleted file mode 100644 index 955b8246..00000000 --- a/lib/tracing/Trace.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Trace.js","sourceRoot":"","sources":["../../src/tracing/Trace.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/tracing/traceSummary.js b/lib/tracing/traceSummary.js deleted file mode 100644 index fb582f90..00000000 --- a/lib/tracing/traceSummary.js +++ /dev/null @@ -1,113 +0,0 @@ -import { getLogger } from "@ui5/logger"; -const log = getLogger("resources:tracing:total"); -import prettyHrtime from "pretty-hrtime"; -const hasOwnProperty = Object.prototype.hasOwnProperty; -let timeoutId; -let active = false; -let tracesRunning = 0; -let traceData; -function init() { - traceData = { - startTime: process.hrtime(), - pathCalls: 0, - globCalls: 0, - collections: {}, - traceCalls: 0 - }; - active = true; -} -function reset() { - traceData = null; - active = false; -} -function report() { - let report = ""; - const time = prettyHrtime(traceData.timeDiff); - const colCount = Object.keys(traceData.collections).length; - report += "==========================\n[=> TRACE SUMMARY:\n"; - report += ` ${time} elapsed time \n`; - report += ` ${traceData.traceCalls} trace calls \n`; - if (traceData.globCalls) { - report += ` ${traceData.globCalls} glob executions\n`; - } - if (traceData.pathCalls) { - report += ` ${traceData.pathCalls} path stats\n`; - } - report += ` ${colCount} rl-collections involed:\n`; - for (const coll in traceData.collections) { - if (hasOwnProperty.call(traceData.collections, coll)) { - report += ` ${traceData.collections[coll].calls}x ${coll}\n`; - } - } - report += "======================]"; - log.silly(report); -} -function someTraceStarted() { - if (!log.isLevelEnabled("silly")) { - return; - } - if (!traceData) { - init(); - } - tracesRunning++; - traceData.traceCalls++; - if (timeoutId) { - clearTimeout(timeoutId); - } -} -function someTraceEnded() { - return new Promise(function (resolve, reject) { - if (!active) { - resolve(); - return; - } - tracesRunning--; - if (tracesRunning > 0) { - resolve(); - return; - } - if (timeoutId) { - clearTimeout(timeoutId); - } - traceData.timeDiff = process.hrtime(traceData.startTime); - timeoutId = setTimeout(function () { - report(); - reset(); - resolve(); - }, 2000); - }); -} -function pathCall() { - if (!active) { - return; - } - traceData.pathCalls++; -} -function globCall() { - if (!active) { - return; - } - traceData.globCalls++; -} -function collection(name) { - if (!active) { - return; - } - const collection = traceData.collections[name]; - if (collection) { - traceData.collections[name].calls++; - } - else { - traceData.collections[name] = { - calls: 1 - }; - } -} -export default { - pathCall: pathCall, - globCall: globCall, - collection: collection, - traceStarted: someTraceStarted, - traceEnded: someTraceEnded -}; -//# sourceMappingURL=traceSummary.js.map \ No newline at end of file diff --git a/lib/tracing/traceSummary.js.map b/lib/tracing/traceSummary.js.map deleted file mode 100644 index b2657e18..00000000 --- a/lib/tracing/traceSummary.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"traceSummary.js","sourceRoot":"","sources":["../../src/tracing/traceSummary.ts"],"names":[],"mappings":"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"} \ No newline at end of file From 81511a851d00d66a08bef61cd0b1955d35737e70 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 13:49:12 +0300 Subject: [PATCH 30/69] refactor: Migrate tests' module references --- src/Resource.ts | 6 ++-- test/lib/AbstractReader.ts | 2 +- test/lib/AbstractReaderWriter.ts | 2 +- test/lib/DuplexCollection.ts | 6 ++-- test/lib/ReaderCollection.ts | 4 +-- test/lib/ReaderCollectionPrioritized.ts | 4 +-- test/lib/Resource.ts | 2 +- test/lib/ResourceFacade.ts | 4 +-- test/lib/ResourceTagCollection.ts | 4 +-- test/lib/WriterCollection.ts | 4 +-- test/lib/adapters/AbstractAdapter.ts | 4 +-- test/lib/adapters/FileSystem.ts | 2 +- test/lib/adapters/FileSystem_read.ts | 4 +-- test/lib/adapters/FileSystem_write.ts | 2 +- .../adapters/FileSystem_write_large_file.ts | 4 +-- test/lib/adapters/Memory_read.ts | 2 +- test/lib/adapters/Memory_write.ts | 2 +- test/lib/fsInterface.ts | 8 +++--- test/lib/glob.ts | 2 +- test/lib/package-exports.ts | 28 +++++++++---------- test/lib/readers/Filter.ts | 2 +- test/lib/readers/Link.ts | 4 +-- test/lib/resourceFactory.ts | 18 ++++++------ test/lib/resources.ts | 2 +- test/lib/tracing/traceSummary.ts | 19 +++++++++---- 25 files changed, 75 insertions(+), 66 deletions(-) diff --git a/src/Resource.ts b/src/Resource.ts index 5c51149a..144c03dd 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -36,7 +36,7 @@ interface Resource_sourceMetadata { export interface Resource_Options { path: string; // It could be a real Stats, but also a Stats like object - statInfo: Partial; + statInfo?: Partial; buffer?: Buffer; string?: string; createStream?: Resource_CreateReadableStream; @@ -124,7 +124,7 @@ class Resource { } for (const metadataKey in sourceMetadata) { // Also check prototype - if (!(metadataKey in ALLOWED_SOURCE_METADATA_KEYS)) { + if (!Object.values(ALLOWED_SOURCE_METADATA_KEYS).includes(metadataKey)) { throw new Error(`Parameter 'sourceMetadata' contains an illegal attribute: ${metadataKey}`); } } @@ -144,7 +144,7 @@ class Resource { this.#project = project; - this.#statInfo = statInfo || { // TODO + this.#statInfo = statInfo ?? { // TODO isFile: fnTrue, isDirectory: fnFalse, isBlockDevice: fnFalse, diff --git a/test/lib/AbstractReader.ts b/test/lib/AbstractReader.ts index db5bf308..9d2fa0bd 100644 --- a/test/lib/AbstractReader.ts +++ b/test/lib/AbstractReader.ts @@ -1,5 +1,5 @@ import test from "ava"; -import AbstractReader from "../../lib/AbstractReader.js"; +import AbstractReader from "../../src/AbstractReader.js"; test("AbstractReader: constructor throws an error", (t) => { t.throws(() => { diff --git a/test/lib/AbstractReaderWriter.ts b/test/lib/AbstractReaderWriter.ts index 768b0c85..7ca55b67 100644 --- a/test/lib/AbstractReaderWriter.ts +++ b/test/lib/AbstractReaderWriter.ts @@ -1,5 +1,5 @@ import test from "ava"; -import AbstractReaderWriter from "../../lib/AbstractReaderWriter.js"; +import AbstractReaderWriter from "../../src/AbstractReaderWriter.js"; test("AbstractReaderWriter: constructor throws an error", (t) => { t.throws(() => { diff --git a/test/lib/DuplexCollection.ts b/test/lib/DuplexCollection.ts index 3ec97ebb..8d25e8b5 100644 --- a/test/lib/DuplexCollection.ts +++ b/test/lib/DuplexCollection.ts @@ -1,8 +1,8 @@ import test from "ava"; import sinon from "sinon"; -import DuplexCollection from "../../lib/DuplexCollection.js"; -import ReaderCollectionPrioritized from "../../lib/ReaderCollectionPrioritized.js"; -import Resource from "../../lib/Resource.js"; +import DuplexCollection from "../../src/DuplexCollection.js"; +import ReaderCollectionPrioritized from "../../src/ReaderCollectionPrioritized.js"; +import Resource from "../../src/Resource.js"; test("DuplexCollection: constructor", (t) => { const duplexCollection = new DuplexCollection({ diff --git a/test/lib/ReaderCollection.ts b/test/lib/ReaderCollection.ts index 8edbc0c6..63949291 100644 --- a/test/lib/ReaderCollection.ts +++ b/test/lib/ReaderCollection.ts @@ -1,7 +1,7 @@ import test from "ava"; import sinon from "sinon"; -import ReaderCollection from "../../lib/ReaderCollection.js"; -import Resource from "../../lib/Resource.js"; +import ReaderCollection from "../../src/ReaderCollection.js"; +import Resource from "../../src/Resource.js"; test("ReaderCollection: constructor", (t) => { const readerCollection = new ReaderCollection({ diff --git a/test/lib/ReaderCollectionPrioritized.ts b/test/lib/ReaderCollectionPrioritized.ts index a0579a73..fe6a4444 100644 --- a/test/lib/ReaderCollectionPrioritized.ts +++ b/test/lib/ReaderCollectionPrioritized.ts @@ -1,7 +1,7 @@ import test from "ava"; import sinon from "sinon"; -import ReaderCollectionPrioritized from "../../lib/ReaderCollectionPrioritized.js"; -import Resource from "../../lib/Resource.js"; +import ReaderCollectionPrioritized from "../../src/ReaderCollectionPrioritized.js"; +import Resource from "../../src/Resource.js"; test("ReaderCollectionPrioritized: constructor", (t) => { const readerCollectionPrioritized = new ReaderCollectionPrioritized({ diff --git a/test/lib/Resource.ts b/test/lib/Resource.ts index f33a2878..11abb491 100644 --- a/test/lib/Resource.ts +++ b/test/lib/Resource.ts @@ -2,7 +2,7 @@ import test from "ava"; import {Stream, Transform} from "node:stream"; import {promises as fs, createReadStream} from "node:fs"; import path from "node:path"; -import Resource from "../../lib/Resource.js"; +import Resource from "../../src/Resource.js"; function createBasicResource() { const fsPath = path.join("test", "fixtures", "application.a", "webapp", "index.html"); diff --git a/test/lib/ResourceFacade.ts b/test/lib/ResourceFacade.ts index eb2c8798..2d57b34a 100644 --- a/test/lib/ResourceFacade.ts +++ b/test/lib/ResourceFacade.ts @@ -1,7 +1,7 @@ import test from "ava"; import sinon from "sinon"; -import Resource from "../../lib/Resource.js"; -import ResourceFacade from "../../lib/ResourceFacade.js"; +import Resource from "../../src/Resource.js"; +import ResourceFacade from "../../src/ResourceFacade.js"; test.afterEach.always((t) => { sinon.restore(); diff --git a/test/lib/ResourceTagCollection.ts b/test/lib/ResourceTagCollection.ts index 54174469..a457f20a 100644 --- a/test/lib/ResourceTagCollection.ts +++ b/test/lib/ResourceTagCollection.ts @@ -1,7 +1,7 @@ import test from "ava"; import sinon from "sinon"; -import Resource from "../../lib/Resource.js"; -import ResourceTagCollection from "../../lib/ResourceTagCollection.js"; +import Resource from "../../src/Resource.js"; +import ResourceTagCollection from "../../src/ResourceTagCollection.js"; test.afterEach.always((t) => { sinon.restore(); diff --git a/test/lib/WriterCollection.ts b/test/lib/WriterCollection.ts index 736c1c2a..ee6b50fe 100644 --- a/test/lib/WriterCollection.ts +++ b/test/lib/WriterCollection.ts @@ -1,7 +1,7 @@ import test from "ava"; import sinon from "sinon"; -import WriterCollection from "../../lib/WriterCollection.js"; -import Resource from "../../lib/Resource.js"; +import WriterCollection from "../../src/WriterCollection.js"; +import Resource from "../../src/Resource.js"; test("Constructor: Path mapping regex", (t) => { const myWriter = {}; diff --git a/test/lib/adapters/AbstractAdapter.ts b/test/lib/adapters/AbstractAdapter.ts index 7b8ed299..4732de71 100644 --- a/test/lib/adapters/AbstractAdapter.ts +++ b/test/lib/adapters/AbstractAdapter.ts @@ -1,6 +1,6 @@ import test from "ava"; -import AbstractAdapter from "../../../lib/adapters/AbstractAdapter.js"; -import {createResource} from "../../../lib/resourceFactory.js"; +import AbstractAdapter from "../../../src/adapters/AbstractAdapter.js"; +import {createResource} from "../../../src/resourceFactory.js"; class MyAbstractAdapter extends AbstractAdapter { } diff --git a/test/lib/adapters/FileSystem.ts b/test/lib/adapters/FileSystem.ts index cfcc9d1a..fa45bdca 100644 --- a/test/lib/adapters/FileSystem.ts +++ b/test/lib/adapters/FileSystem.ts @@ -1,6 +1,6 @@ import test from "ava"; -import FileSystem from "../../../lib/adapters/FileSystem.js"; +import FileSystem from "../../../src/adapters/FileSystem.js"; test.serial("Missing parameter: fsBasePath", (t) => { t.throws(() => { diff --git a/test/lib/adapters/FileSystem_read.ts b/test/lib/adapters/FileSystem_read.ts index 65bb99a0..e7f6c754 100644 --- a/test/lib/adapters/FileSystem_read.ts +++ b/test/lib/adapters/FileSystem_read.ts @@ -2,7 +2,7 @@ import test from "ava"; import sinon from "sinon"; import esmock from "esmock"; import path from "node:path"; -import {createAdapter} from "../../../lib/resourceFactory.js"; +import {createAdapter} from "../../../src/resourceFactory.js"; test("glob resources from application.a w/ virtual base path prefix", async (t) => { const readerWriter = createAdapter({ @@ -553,7 +553,7 @@ test("byPath with useGitignore: true", async (t) => { const {isGitIgnored} = await import("globby"); const isGitIgnoredSpy = sinon.stub().callsFake(isGitIgnored); - const FileSystem = await esmock("../../../lib/adapters/FileSystem.js", { + const FileSystem = await esmock("../../../src/adapters/FileSystem.js", { globby: { isGitIgnored: isGitIgnoredSpy, }, diff --git a/test/lib/adapters/FileSystem_write.ts b/test/lib/adapters/FileSystem_write.ts index 99927d47..c3f7eabe 100644 --- a/test/lib/adapters/FileSystem_write.ts +++ b/test/lib/adapters/FileSystem_write.ts @@ -6,7 +6,7 @@ import test from "ava"; import {rimraf} from "rimraf"; import sinon from "sinon"; -import {createAdapter, createResource} from "../../../lib/resourceFactory.js"; +import {createAdapter, createResource} from "../../../src/resourceFactory.js"; function getFileContent(path) { return readFile(path, "utf8"); diff --git a/test/lib/adapters/FileSystem_write_large_file.ts b/test/lib/adapters/FileSystem_write_large_file.ts index f812470b..cea40f69 100644 --- a/test/lib/adapters/FileSystem_write_large_file.ts +++ b/test/lib/adapters/FileSystem_write_large_file.ts @@ -3,8 +3,8 @@ import {fileURLToPath} from "node:url"; import {Buffer} from "node:buffer"; import {readFile} from "node:fs/promises"; -import FileSystem from "../../../lib/adapters/FileSystem.js"; -import Resource from "../../../lib/Resource.js"; +import FileSystem from "../../../src/adapters/FileSystem.js"; +import Resource from "../../../src/Resource.js"; import path from "node:path"; test.serial("Stream a large file from source to target", async (t) => { diff --git a/test/lib/adapters/Memory_read.ts b/test/lib/adapters/Memory_read.ts index 735fa206..9e468cbe 100644 --- a/test/lib/adapters/Memory_read.ts +++ b/test/lib/adapters/Memory_read.ts @@ -1,5 +1,5 @@ import test from "ava"; -import {createAdapter, createResource} from "../../../lib/resourceFactory.js"; +import {createAdapter, createResource} from "../../../src/resourceFactory.js"; async function fillFromFs(readerWriter, {fsBasePath = "./test/fixtures/glob", virBasePath = "/app/"} = {}) { const fsReader = createAdapter({ diff --git a/test/lib/adapters/Memory_write.ts b/test/lib/adapters/Memory_write.ts index b9863c8b..437eddb8 100644 --- a/test/lib/adapters/Memory_write.ts +++ b/test/lib/adapters/Memory_write.ts @@ -1,5 +1,5 @@ import test from "ava"; -import {createAdapter, createResource} from "../../../lib/resourceFactory.js"; +import {createAdapter, createResource} from "../../../src/resourceFactory.js"; import sinon from "sinon"; test("glob resources from application.a w/ virtual base path prefix", async (t) => { diff --git a/test/lib/fsInterface.ts b/test/lib/fsInterface.ts index c0f7df9c..788ece66 100644 --- a/test/lib/fsInterface.ts +++ b/test/lib/fsInterface.ts @@ -6,10 +6,10 @@ import {fileURLToPath} from "node:url"; import fsSync from "node:fs"; const stat = promisify(fsSync.stat); import {readFile} from "node:fs/promises"; -import fsInterface from "../../lib/fsInterface.js"; -import MemAdapter from "../../lib/adapters/Memory.js"; -import FsAdapter from "../../lib/adapters/FileSystem.js"; -import Resource from "../../lib/Resource.js"; +import fsInterface from "../../src/fsInterface.js"; +import MemAdapter from "../../src/adapters/Memory.js"; +import FsAdapter from "../../src/adapters/FileSystem.js"; +import Resource from "../../src/Resource.js"; const assertReadFile = async (t, readFile, basepath, filepath, content) => { content = content || "content of " + filepath; diff --git a/test/lib/glob.ts b/test/lib/glob.ts index 6e84564f..40ebdadb 100644 --- a/test/lib/glob.ts +++ b/test/lib/glob.ts @@ -1,5 +1,5 @@ import test from "ava"; -import FsAdapter from "../../lib/adapters/FileSystem.js"; +import FsAdapter from "../../src/adapters/FileSystem.js"; // Create readerWriter before running tests test.beforeEach((t) => { diff --git a/test/lib/package-exports.ts b/test/lib/package-exports.ts index bf8b0fba..3214c140 100644 --- a/test/lib/package-exports.ts +++ b/test/lib/package-exports.ts @@ -19,60 +19,60 @@ test("check number of exports", (t) => { [ { exportedSpecifier: "@ui5/fs/adapters/AbstractAdapter", - mappedModule: "../../lib/adapters/AbstractAdapter.js", + mappedModule: "../../src/adapters/AbstractAdapter.js", }, { exportedSpecifier: "@ui5/fs/adapters/FileSystem", - mappedModule: "../../lib/adapters/FileSystem.js", + mappedModule: "../../src/adapters/FileSystem.js", }, { exportedSpecifier: "@ui5/fs/adapters/Memory", - mappedModule: "../../lib/adapters/Memory.js", + mappedModule: "../../src/adapters/Memory.js", }, { exportedSpecifier: "@ui5/fs/AbstractReader", - mappedModule: "../../lib/AbstractReader.js", + mappedModule: "../../src/AbstractReader.js", }, { exportedSpecifier: "@ui5/fs/AbstractReaderWriter", - mappedModule: "../../lib/AbstractReaderWriter.js", + mappedModule: "../../src/AbstractReaderWriter.js", }, { exportedSpecifier: "@ui5/fs/DuplexCollection", - mappedModule: "../../lib/DuplexCollection.js", + mappedModule: "../../src/DuplexCollection.js", }, { exportedSpecifier: "@ui5/fs/fsInterface", - mappedModule: "../../lib/fsInterface.js", + mappedModule: "../../src/fsInterface.js", }, { exportedSpecifier: "@ui5/fs/ReaderCollection", - mappedModule: "../../lib/ReaderCollection.js", + mappedModule: "../../src/ReaderCollection.js", }, { exportedSpecifier: "@ui5/fs/ReaderCollectionPrioritized", - mappedModule: "../../lib/ReaderCollectionPrioritized.js", + mappedModule: "../../src/ReaderCollectionPrioritized.js", }, { exportedSpecifier: "@ui5/fs/readers/Filter", - mappedModule: "../../lib/readers/Filter.js", + mappedModule: "../../src/readers/Filter.js", }, { exportedSpecifier: "@ui5/fs/readers/Link", - mappedModule: "../../lib/readers/Link.js", + mappedModule: "../../src/readers/Link.js", }, { exportedSpecifier: "@ui5/fs/Resource", - mappedModule: "../../lib/Resource.js", + mappedModule: "../../src/Resource.js", }, { exportedSpecifier: "@ui5/fs/resourceFactory", - mappedModule: "../../lib/resourceFactory.js", + mappedModule: "../../src/resourceFactory.js", }, // Internal modules (only to be used by @ui5/* packages) { exportedSpecifier: "@ui5/fs/internal/ResourceTagCollection", - mappedModule: "../../lib/ResourceTagCollection.js", + mappedModule: "../../src/ResourceTagCollection.js", }, ].forEach(({exportedSpecifier, mappedModule}) => { test(`${exportedSpecifier}`, async (t) => { diff --git a/test/lib/readers/Filter.ts b/test/lib/readers/Filter.ts index 5550ecf5..d9bfb8a7 100644 --- a/test/lib/readers/Filter.ts +++ b/test/lib/readers/Filter.ts @@ -1,6 +1,6 @@ import test from "ava"; import sinon from "sinon"; -import Filter from "../../../lib/readers/Filter.js"; +import Filter from "../../../src/readers/Filter.js"; test("_byGlob: Basic filter", async (t) => { const abstractReader = { diff --git a/test/lib/readers/Link.ts b/test/lib/readers/Link.ts index 2498b923..230513bc 100644 --- a/test/lib/readers/Link.ts +++ b/test/lib/readers/Link.ts @@ -1,7 +1,7 @@ import test from "ava"; import sinon from "sinon"; -import Link from "../../../lib/readers/Link.js"; -import ResourceFacade from "../../../lib/ResourceFacade.js"; +import Link from "../../../src/readers/Link.js"; +import ResourceFacade from "../../../src/ResourceFacade.js"; test("_byGlob: Basic Link", async (t) => { const dummyResourceA = { diff --git a/test/lib/resourceFactory.ts b/test/lib/resourceFactory.ts index f0c1df45..27c2d0ab 100644 --- a/test/lib/resourceFactory.ts +++ b/test/lib/resourceFactory.ts @@ -1,10 +1,10 @@ import test from "ava"; import { createAdapter, createReader, createReaderCollection, createReaderCollectionPrioritized, - createResource, createWriterCollection, createWorkspace, prefixGlobPattern} from "../../lib/resourceFactory.js"; -import FileSystem from "../../lib/adapters/FileSystem.js"; -import Memory from "../../lib/adapters/Memory.js"; -import ReaderCollection from "../../lib/ReaderCollection.js"; + createResource, createWriterCollection, createWorkspace, prefixGlobPattern} from "../../src/resourceFactory.js"; +import FileSystem from "../../src/adapters/FileSystem.js"; +import Memory from "../../src/adapters/Memory.js"; +import ReaderCollection from "../../src/ReaderCollection.js"; import {setLogLevel} from "@ui5/logger"; // Set log level to silly to activate tracing @@ -230,7 +230,7 @@ test("createReaderCollection", async (t) => { }); test("createReaderCollectionPrioritized", async (t) => { - const {default: ReaderCollectionPrioritized} = await import("../../lib/ReaderCollectionPrioritized.js"); + const {default: ReaderCollectionPrioritized} = await import("../../src/ReaderCollectionPrioritized.js"); const adapter = createAdapter({ virBasePath: "/resources/app/", project: { @@ -260,7 +260,7 @@ test("createReaderCollectionPrioritized", async (t) => { }); test("createWriterCollection", async (t) => { - const {default: WriterCollection} = await import("../../lib/WriterCollection.js"); + const {default: WriterCollection} = await import("../../src/WriterCollection.js"); const adapter1 = createAdapter({ virBasePath: "/", project: { @@ -300,7 +300,7 @@ test("createWriterCollection", async (t) => { }); test("createWorkspace", async (t) => { - const {default: DuplexCollection} = await import("../../lib/DuplexCollection.js"); + const {default: DuplexCollection} = await import("../../src/DuplexCollection.js"); const reader = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", virBasePath: "/resources/app/", @@ -333,8 +333,8 @@ test("createWorkspace", async (t) => { }); test("createWorkspace: Without writer", async (t) => { - const {default: DuplexCollection} = await import("../../lib/DuplexCollection.js"); - const {default: Memory} = await import("../../lib/adapters/Memory.js"); + const {default: DuplexCollection} = await import("../../src/DuplexCollection.js"); + const {default: Memory} = await import("../../src/adapters/Memory.js"); const reader = createAdapter({ fsBasePath: "./test/fixtures/application.a/webapp", virBasePath: "/resources/app/", diff --git a/test/lib/resources.ts b/test/lib/resources.ts index 4674ae23..415e2500 100644 --- a/test/lib/resources.ts +++ b/test/lib/resources.ts @@ -3,7 +3,7 @@ import sinon from "sinon"; import {readFile} from "node:fs/promises"; import {createAdapter, createFilterReader, - createFlatReader, createLinkReader, createResource} from "../../lib/resourceFactory.js"; + createFlatReader, createLinkReader, createResource} from "../../src/resourceFactory.js"; test.afterEach.always((_t) => { sinon.restore(); diff --git a/test/lib/tracing/traceSummary.ts b/test/lib/tracing/traceSummary.ts index 3d2de477..0ab8f175 100644 --- a/test/lib/tracing/traceSummary.ts +++ b/test/lib/tracing/traceSummary.ts @@ -1,15 +1,24 @@ -import test from "ava"; -import sinon from "sinon"; -import esmock from "esmock"; +import anyTest, {TestFn, ExecutionContext} from "ava"; +import sinon, {SinonStub} from "sinon"; +import esmock, {MockFunction} from "esmock"; + +interface avaContext { + loggerStub: { + silly: SinonStub; + isLevelEnabled: (arg: boolean) => boolean; + }; + traceSummary: MockFunction; +} +const test = anyTest as TestFn; -async function createMock(t, isLevelEnabled = true) { +async function createMock(t: ExecutionContext, isLevelEnabled = true) { t.context.loggerStub = { silly: sinon.stub(), isLevelEnabled: () => { return isLevelEnabled; }, }; - t.context.traceSummary = await esmock("../../../lib/tracing/traceSummary.js", { + t.context.traceSummary = await esmock("../../../src/tracing/traceSummary.js", { "@ui5/logger": { getLogger: sinon.stub().returns(t.context.loggerStub), }, From 261711af3b85437490214e963737263b5de80a60 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 14:04:44 +0300 Subject: [PATCH 31/69] refactor: Align configurations --- eslint.common.config.js | 23 ++++++++++++++++++++++- package.json | 4 +++- typedoc.config.js | 10 ++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 typedoc.config.js diff --git a/eslint.common.config.js b/eslint.common.config.js index 24daf30b..5a020740 100644 --- a/eslint.common.config.js +++ b/eslint.common.config.js @@ -1,6 +1,8 @@ import eslint from "@eslint/js"; import tseslint from "typescript-eslint"; import stylistic from "@stylistic/eslint-plugin"; +import ava from "eslint-plugin-ava"; +import jsdoc from "eslint-plugin-jsdoc"; export default tseslint.config( { @@ -10,6 +12,8 @@ export default tseslint.config( ".github/*", ".reuse/*", "coverage/*", + "**/docs/", + "**/jsdocs/", // Exclude test files "test/tmp/*", @@ -29,7 +33,8 @@ export default tseslint.config( arrowParens: true, braceStyle: "1tbs", blockSpacing: false, - }), { + }), + ava.configs["flat/recommended"], { // Lint all JS files using the eslint parser files: ["**/*.js"], languageOptions: { @@ -113,6 +118,22 @@ export default tseslint.config( ], "no-console": "error", "no-eval": "error", + + "valid-jsdoc": 0, + }, + }, { + // JSdoc only applying to sources + files: ["src/**/*.ts"], + ...jsdoc.configs["flat/recommended-typescript-error"], + }, { + // Overwriting JSDoc rules in a separate config with the same files pattern + files: ["src/**/*.ts"], + rules: { + "jsdoc/require-returns": 0, + "jsdoc/require-returns-description": 0, + "jsdoc/tag-lines": [2, "any", { + startLines: 1, + }], }, } ); diff --git a/package.json b/package.json index fb1d629f..8b12aba8 100644 --- a/package.json +++ b/package.json @@ -148,6 +148,8 @@ "sinon": "^18.0.0", "tap-xunit": "^2.4.1", "tsx": "^4.17.0", - "typescript-eslint": "^8.2.0" + "typescript-eslint": "^8.2.0", + "typedoc": "^0.26.6", + "typedoc-plugin-rename-defaults": "^0.7.1" } } diff --git a/typedoc.config.js b/typedoc.config.js new file mode 100644 index 00000000..080f4c02 --- /dev/null +++ b/typedoc.config.js @@ -0,0 +1,10 @@ +/** @type {Partial} */ +const config = { + entryPoints: ["./src/"], + tsconfig: "tsconfig.build.json", + out: "jsdocs", + entryPointStrategy: "expand", + plugin: ["typedoc-plugin-rename-defaults"], +}; + +export default config; From ea72bf5391bcfd980b3a6c1f36c246fd6b905fe3 Mon Sep 17 00:00:00 2001 From: Max Reichmann Date: Tue, 27 Aug 2024 14:01:09 +0200 Subject: [PATCH 32/69] refactor: Add ResourceInterface --- src/AbstractReader.ts | 24 +++++++++++----------- src/Resource.ts | 23 ++++++++++++++++++++- src/ResourceFacade.ts | 10 +++++----- src/readers/Filter.ts | 8 ++++---- src/readers/Link.ts | 45 ++++++++++++++++++++++++------------------ src/resourceFactory.ts | 2 +- 6 files changed, 70 insertions(+), 42 deletions(-) diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index e55d42df..f24abf49 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -1,6 +1,6 @@ import randomInt from "random-int"; import Trace from "./tracing/Trace.js"; -import Resource from "./Resource.js"; +import {ResourceInterface} from "./Resource.js"; /** * Abstract resource locator implementing the general API for reading resources @@ -49,12 +49,12 @@ class AbstractReader { * @param {boolean} [options.nodir=true] Do not match directories * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - byGlob(virPattern: string, options = {nodir: true}): Promise { + byGlob(virPattern: string, options = {nodir: true}): Promise { const trace = new Trace(virPattern); - return this._byGlob(virPattern, options, trace).then(function (result: Resource[]) { + return this._byGlob(virPattern, options, trace).then(function (result: ResourceInterface[]) { trace.printReport(); return result; - }).then((resources: Resource[]) => { + }).then((resources: ResourceInterface[]) => { if (resources.length > 1) { // Pseudo randomize result order to prevent consumers from relying on it: // Swap the first object with a randomly chosen one @@ -74,9 +74,9 @@ class AbstractReader { * @param {string} virPath Virtual path * @param {object} [options] Options * @param {boolean} [options.nodir=true] Do not match directories - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + * @returns {Promise<@ui5/fs/ResourceInterface>} Promise resolving to a single resource */ - byPath(virPath: string, options = {nodir: true}): Promise { + byPath(virPath: string, options = {nodir: true}): Promise { const trace = new Trace(virPath); return this._byPath(virPath, options, trace).then(function (resource) { trace.printReport(); @@ -93,13 +93,13 @@ class AbstractReader { * glob patterns for virtual directory structure * @param {object} options glob options * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + * @returns {Promise<@ui5/fs/ResourceInterface[]>} Promise resolving to list of resources */ _byGlob(_virPattern: string | string[], _options: { nodir: boolean; }, - _trace: Trace): Promise { + _trace: Trace): Promise { throw new Error("Function '_byGlob' is not implemented"); } @@ -111,9 +111,9 @@ class AbstractReader { * @param {string|string[]} pattern glob pattern * @param {object} options glob options * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + * @returns {Promise<@ui5/fs/ResourceInterface[]>} Promise resolving to list of resources */ - _runGlob(_pattern: string | string[], _options: {nodir: boolean}, _trace: Trace): Promise { + _runGlob(_pattern: string | string[], _options: {nodir: boolean}, _trace: Trace): Promise { throw new Error("Function '_runGlob' is not implemented"); } @@ -125,9 +125,9 @@ class AbstractReader { * @param {string} virPath Virtual path * @param {object} options Options * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + * @returns {Promise<@ui5/fs/ResourceInterface>} Promise resolving to a single resource */ - _byPath(_virPath: string, _options: object, _trace: Trace): Promise { + _byPath(_virPath: string, _options: object, _trace: Trace): Promise { throw new Error("Function '_byPath' is not implemented"); } } diff --git a/src/Resource.ts b/src/Resource.ts index 144c03dd..98f6dc26 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -63,6 +63,27 @@ export interface LegacyResource { _getBufferFromStream: () => Promise; } +export interface ResourceInterface { + clone(): Promise; + getBuffer(): Promise; + getName(): string; + getPath(): string; + getPathTree(): Tree; + getProject(): Project | undefined; + getSourceMetadata(): Resource_sourceMetadata; + getSize(): Promise; + getStatInfo(): Partial; + getStream(): stream.Readable; + getString(): Promise; + hasProject(): boolean; + isModified(): boolean; + pushCollection(name: string): void; + setBuffer(buffer: Buffer): void; + setPath(path: string): void; + setProject(project: Project): void; + setStream(stream: stream.Readable | Resource_CreateReadableStream): void; + setString(string: string): void; +} /** * Resource. UI5 Tooling specific representation of a file's content and metadata * @@ -70,7 +91,7 @@ export interface LegacyResource { * @class * @alias @ui5/fs/Resource */ -class Resource { +class Resource implements ResourceInterface { #project; #buffer: Buffer | null | undefined; #buffering: Promise | null | undefined; diff --git a/src/ResourceFacade.ts b/src/ResourceFacade.ts index d7f7eabc..81f56572 100644 --- a/src/ResourceFacade.ts +++ b/src/ResourceFacade.ts @@ -1,5 +1,5 @@ import posixPath from "node:path/posix"; -import Resource from "./Resource.js"; +import {ResourceInterface} from "./Resource.js"; import {Buffer} from "node:buffer"; import stream from "node:stream"; import {Resource_CreateReadableStream} from "./Resource.js"; @@ -12,7 +12,7 @@ import {Project} from "@ui5/project/specifications/Project"; * @class * @alias @ui5/fs/ResourceFacade */ -class ResourceFacade { +class ResourceFacade implements ResourceInterface { #path; #name; #resource; @@ -22,9 +22,9 @@ class ResourceFacade { * @public * @param {object} parameters Parameters * @param {string} parameters.path Virtual path of the facade resource - * @param {@ui5/fs/Resource} parameters.resource Resource to conceal + * @param parameters.resource Resource to conceal */ - constructor({path, resource}: {path: string; resource: Resource}) { + constructor({path, resource}: {path: string; resource: ResourceInterface}) { if (!path) { throw new Error("Unable to create ResourceFacade: Missing parameter 'path'"); } @@ -175,7 +175,7 @@ class ResourceFacade { * @see {TypedArray#byteLength} * @returns {Promise} size in bytes, 0 if there is no content yet */ - async getSize() { + getSize() { return this.#resource.getSize(); } diff --git a/src/readers/Filter.ts b/src/readers/Filter.ts index 426d18a0..55344e2a 100644 --- a/src/readers/Filter.ts +++ b/src/readers/Filter.ts @@ -1,10 +1,10 @@ import AbstractReader from "../AbstractReader.js"; -import Resource from "../Resource.js"; +import {ResourceInterface} from "../Resource.js"; import Trace from "../tracing/Trace.js"; export interface Filter_Params { reader: AbstractReader; - callback: (resource: Resource) => boolean; + callback: (resource: ResourceInterface) => boolean; }; /** @@ -17,7 +17,7 @@ export interface Filter_Params { */ class Filter extends AbstractReader { _reader: AbstractReader; - _callback: (resource: Resource) => boolean; + _callback: (resource: ResourceInterface) => boolean; /** * Filter callback @@ -73,7 +73,7 @@ class Filter extends AbstractReader { * @param {@ui5/fs/tracing/Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - async _byPath(virPath: string, options: {nodir: boolean}, trace: Trace): Promise { + async _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { const result = await this._reader._byPath(virPath, options, trace); if (result && !this._callback(result)) { return null; diff --git a/src/readers/Link.ts b/src/readers/Link.ts index 8ba0b089..f1ff3e93 100644 --- a/src/readers/Link.ts +++ b/src/readers/Link.ts @@ -3,6 +3,7 @@ import ResourceFacade from "../ResourceFacade.js"; import {prefixGlobPattern} from "../resourceFactory.js"; import {getLogger} from "@ui5/logger"; const log = getLogger("resources:readers:Link"); +import Trace from "../tracing/Trace.js"; /** * A reader that allows for rewriting paths segments of all resources passed through it. @@ -27,6 +28,8 @@ const log = getLogger("resources:readers:Link"); * @extends @ui5/fs/AbstractReader */ class Link extends AbstractReader { + _reader: AbstractReader; + _pathMapping: {linkPath: string; targetPath: string}; /** * Path mapping for a [Link]{@link @ui5/fs/readers/Link} * @@ -44,7 +47,7 @@ class Link extends AbstractReader { * @param {@ui5/fs/AbstractReader} parameters.reader The resource reader or collection to wrap * @param {@ui5/fs/readers/Link/PathMapping} parameters.pathMapping */ - constructor({reader, pathMapping}) { + constructor({reader, pathMapping}: {reader: AbstractReader; pathMapping: {linkPath: string; targetPath: string}}) { super(); if (!reader) { throw new Error(`Missing parameter "reader"`); @@ -61,17 +64,18 @@ class Link extends AbstractReader { * Locates resources by glob. * * @private - * @param {string|string[]} patterns glob pattern as string or an array of + * @param {string|string[]} pattern glob pattern as string or an array of * glob patterns for virtual directory structure * @param {object} options glob options * @param {@ui5/fs/tracing/Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources */ - async _byGlob(patterns, options, trace) { - if (!(patterns instanceof Array)) { - patterns = [patterns]; + async _byGlob(pattern: string | string[], options: {nodir: boolean}, trace: Trace) { + if (!(pattern instanceof Array)) { + pattern = [pattern]; } - patterns = patterns.map((pattern) => { + + pattern = pattern.flatMap((pattern) => { if (pattern.startsWith(this._pathMapping.linkPath)) { pattern = pattern.substr(this._pathMapping.linkPath.length); } @@ -79,19 +83,22 @@ class Link extends AbstractReader { }); // Flatten prefixed patterns - patterns = Array.prototype.concat.apply([], patterns); + pattern = Array.prototype.concat.apply([], pattern); // Keep resource's internal path unchanged for now - const resources = await this._reader._byGlob(patterns, options, trace); - return resources.map((resource) => { - const resourcePath = resource.getPath(); - if (resourcePath.startsWith(this._pathMapping.targetPath)) { - return new ResourceFacade({ - resource, - path: this._pathMapping.linkPath + resourcePath.substr(this._pathMapping.targetPath.length), - }); - } - }); + const resources = await this._reader._byGlob(pattern, options, trace); + + return resources + .map((resource) => { + const resourcePath = resource.getPath(); + if (resourcePath.startsWith(this._pathMapping.targetPath)) { + return new ResourceFacade({ + resource, + path: this._pathMapping.linkPath + resourcePath.substr(this._pathMapping.targetPath.length), + }); + } + }) + .filter((resource) => resource !== undefined); } /** @@ -103,7 +110,7 @@ class Link extends AbstractReader { * @param {@ui5/fs/tracing/Trace} trace Trace instance * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource */ - async _byPath(virPath, options, trace) { + async _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { if (!virPath.startsWith(this._pathMapping.linkPath)) { return null; } @@ -120,7 +127,7 @@ class Link extends AbstractReader { return null; } - static _validatePathMapping({linkPath, targetPath}) { + static _validatePathMapping({linkPath, targetPath}: {linkPath: string; targetPath: string}) { if (!linkPath) { throw new Error(`Path mapping is missing attribute "linkPath"`); } diff --git a/src/resourceFactory.ts b/src/resourceFactory.ts index f0eead34..3c8637eb 100644 --- a/src/resourceFactory.ts +++ b/src/resourceFactory.ts @@ -273,7 +273,7 @@ export function createFlatReader({reader, namespace}: {reader: AbstractReader; n * @param {string} virBaseDir virtual base directory path to prefix the given patterns with * @returns {string[]} A list of normalized glob patterns */ -export function prefixGlobPattern(virPattern: string, virBaseDir: string) { +export function prefixGlobPattern(virPattern: string, virBaseDir: string): string[] { const mm = new minimatch.Minimatch(virPattern); const resultGlobs = []; From 3e9384bf784b3a46def47224ef43424d6ee77166 Mon Sep 17 00:00:00 2001 From: Max Reichmann Date: Tue, 27 Aug 2024 14:16:53 +0200 Subject: [PATCH 33/69] refactor: Fix ESLint error --- src/Resource.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Resource.ts b/src/Resource.ts index 98f6dc26..67b4f14a 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -145,7 +145,8 @@ class Resource implements ResourceInterface { } for (const metadataKey in sourceMetadata) { // Also check prototype - if (!Object.values(ALLOWED_SOURCE_METADATA_KEYS).includes(metadataKey)) { + if (!Object.values(ALLOWED_SOURCE_METADATA_KEYS) + .includes(metadataKey as ALLOWED_SOURCE_METADATA_KEYS)) { throw new Error(`Parameter 'sourceMetadata' contains an illegal attribute: ${metadataKey}`); } } From e53118eab13476384d07f8b42a97187ae82d1cc3 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 15:22:34 +0300 Subject: [PATCH 34/69] fix: Tests --- src/Resource.ts | 5 +++++ src/utils/tsUtils.ts | 2 +- test/lib/Resource.ts | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Resource.ts b/src/Resource.ts index 67b4f14a..7b187034 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -149,6 +149,11 @@ class Resource implements ResourceInterface { .includes(metadataKey as ALLOWED_SOURCE_METADATA_KEYS)) { throw new Error(`Parameter 'sourceMetadata' contains an illegal attribute: ${metadataKey}`); } + if (!["string", "boolean"].includes(typeof sourceMetadata[metadataKey])) { + throw new Error( + `Attribute '${metadataKey}' of parameter 'sourceMetadata' ` + + `must be of type "string" or "boolean"`); + } } } diff --git a/src/utils/tsUtils.ts b/src/utils/tsUtils.ts index 32e65f25..e1cb90d6 100644 --- a/src/utils/tsUtils.ts +++ b/src/utils/tsUtils.ts @@ -1,7 +1,7 @@ import Resource from "../Resource.js"; export function isString(testString: unknown): testString is string { - return testString instanceof String; + return testString instanceof String || String(testString) === testString; } export function isLegacyResource(resource: unknown): resource is Resource { diff --git a/test/lib/Resource.ts b/test/lib/Resource.ts index 11abb491..f79c5b29 100644 --- a/test/lib/Resource.ts +++ b/test/lib/Resource.ts @@ -651,7 +651,7 @@ test("Resource: reassign with setProject", (t) => { const project = {getName: () => "New Mock Project"}; const error = t.throws(() => resource.setProject(project)); t.is(error.message, "Unable to assign project New Mock Project to resource /my/path/to/resource: " + - "Resource is already associated to project " + project); + "Resource is already associated to project Mock Project"); }); test("Resource: constructor with stream", async (t) => { From 9e808f161418e34dbb4099e193d9463ef9fd0041 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 15:26:10 +0300 Subject: [PATCH 35/69] refactor: Resource --- src/Resource.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Resource.ts b/src/Resource.ts index 7b187034..94b0ac55 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -144,12 +144,16 @@ class Resource implements ResourceInterface { throw new Error(`Parameter 'sourceMetadata' must be of type "object"`); } + // TODO: TS Those checks are completely redundant, but some tests + // and maybe runtime code would rely on them. A major refactoring + // would be needed for (const metadataKey in sourceMetadata) { // Also check prototype if (!Object.values(ALLOWED_SOURCE_METADATA_KEYS) .includes(metadataKey as ALLOWED_SOURCE_METADATA_KEYS)) { throw new Error(`Parameter 'sourceMetadata' contains an illegal attribute: ${metadataKey}`); } - if (!["string", "boolean"].includes(typeof sourceMetadata[metadataKey])) { + if (!["string", "boolean"] + .includes(typeof sourceMetadata[metadataKey as ALLOWED_SOURCE_METADATA_KEYS])) { throw new Error( `Attribute '${metadataKey}' of parameter 'sourceMetadata' ` + `must be of type "string" or "boolean"`); From 0949eb2bfa260fcb331d17b968198959f6a3cd47 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 15:31:30 +0300 Subject: [PATCH 36/69] refactor: Correct export modules from package.json --- package.json | 22 +++++++++++----------- src/Resource.ts | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 8b12aba8..6c8bacb2 100644 --- a/package.json +++ b/package.json @@ -18,18 +18,18 @@ ], "type": "module", "exports": { - "./adapters/*": "./lib/adapters/*.js", - "./AbstractReader": "./lib/AbstractReader.js", - "./AbstractReaderWriter": "./lib/AbstractReaderWriter.js", - "./DuplexCollection": "./lib/DuplexCollection.js", - "./fsInterface": "./lib/fsInterface.js", - "./readers/*": "./lib/readers/*.js", - "./ReaderCollection": "./lib/ReaderCollection.js", - "./ReaderCollectionPrioritized": "./lib/ReaderCollectionPrioritized.js", - "./Resource": "./lib/Resource.js", - "./resourceFactory": "./lib/resourceFactory.js", + "./adapters/*": "./src/adapters/*.ts", + "./AbstractReader": "./src/AbstractReader.ts", + "./AbstractReaderWriter": "./src/AbstractReaderWriter.ts", + "./DuplexCollection": "./src/DuplexCollection.ts", + "./fsInterface": "./src/fsInterface.ts", + "./readers/*": "./src/readers/*.ts", + "./ReaderCollection": "./src/ReaderCollection.ts", + "./ReaderCollectionPrioritized": "./src/ReaderCollectionPrioritized.ts", + "./Resource": "./src/Resource.ts", + "./resourceFactory": "./src/resourceFactory.ts", "./package.json": "./package.json", - "./internal/ResourceTagCollection": "./lib/ResourceTagCollection.js" + "./internal/ResourceTagCollection": "./src/ResourceTagCollection.ts" }, "engines": { "node": "^20.11.0 || >=22.0.0", diff --git a/src/Resource.ts b/src/Resource.ts index 94b0ac55..1b5c0dd7 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -145,7 +145,7 @@ class Resource implements ResourceInterface { } // TODO: TS Those checks are completely redundant, but some tests - // and maybe runtime code would rely on them. A major refactoring + // and maybe runtime code would rely on them. A major refactoring // would be needed for (const metadataKey in sourceMetadata) { // Also check prototype if (!Object.values(ALLOWED_SOURCE_METADATA_KEYS) From ca239723e3bf297034e3a1522435d4029a4db57c Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 15:36:44 +0300 Subject: [PATCH 37/69] fix: Tests --- src/Resource.ts | 2 +- src/adapters/AbstractAdapter.ts | 4 ++-- src/utils/tsUtils.ts | 4 ++-- test/lib/adapters/AbstractAdapter.ts | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Resource.ts b/src/Resource.ts index 1b5c0dd7..6c5d53b2 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -60,7 +60,7 @@ export interface LegacyResource { _createStream?: Resource_CreateReadableStream; _stream?: stream.Readable; _buffer?: Buffer; - _getBufferFromStream: () => Promise; + _getBufferFromStream?: () => Promise; } export interface ResourceInterface { diff --git a/src/adapters/AbstractAdapter.ts b/src/adapters/AbstractAdapter.ts index b694bc72..2a395f0c 100644 --- a/src/adapters/AbstractAdapter.ts +++ b/src/adapters/AbstractAdapter.ts @@ -7,7 +7,7 @@ import AbstractReaderWriter from "../AbstractReaderWriter.js"; import Resource, {Resource_Options, LegacyResource} from "../Resource.js"; import type {Project} from "@ui5/project/specifications/Project"; import Trace from "../tracing/Trace.js"; -import {isLegacyResource} from "../utils/tsUtils.js"; +import {isMigratedResource} from "../utils/tsUtils.js"; /** * Abstract Resource Adapter @@ -221,7 +221,7 @@ class AbstractAdapter extends AbstractReaderWriter { // Check if its a fs/Resource v3, function 'hasProject' was // introduced with v3 therefore take it as the indicator - if (isLegacyResource(resource)) { + if (isMigratedResource(resource)) { return resource; } return this._createFromLegacyResource(resource); diff --git a/src/utils/tsUtils.ts b/src/utils/tsUtils.ts index e1cb90d6..c54c2115 100644 --- a/src/utils/tsUtils.ts +++ b/src/utils/tsUtils.ts @@ -4,8 +4,8 @@ export function isString(testString: unknown): testString is string { return testString instanceof String || String(testString) === testString; } -export function isLegacyResource(resource: unknown): resource is Resource { +export function isMigratedResource(resource: unknown): resource is Resource { // Check if its a fs/Resource v3, function 'hasProject' was // introduced with v3 therefore take it as the indicator - return !!resource && !Object.hasOwnProperty.call(resource, "hasProject"); + return !!resource && !!Object.hasOwnProperty.call(resource, "hasProject"); } diff --git a/test/lib/adapters/AbstractAdapter.ts b/test/lib/adapters/AbstractAdapter.ts index 4732de71..1f13a889 100644 --- a/test/lib/adapters/AbstractAdapter.ts +++ b/test/lib/adapters/AbstractAdapter.ts @@ -1,6 +1,7 @@ import test from "ava"; import AbstractAdapter from "../../../src/adapters/AbstractAdapter.js"; import {createResource} from "../../../src/resourceFactory.js"; +import { LegacyResource } from "../../../src/Resource.js"; class MyAbstractAdapter extends AbstractAdapter { } @@ -34,7 +35,7 @@ test("virBasePath must end with a slash", (t) => { test("_migrateResource", async (t) => { // Any JS object which might be a kind of resource - const resource = { + const resource: LegacyResource = { _path: "/test.js", }; From ccc80f5d7a9fe9edcc7f1a6392d46f60f5885543 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 15:37:52 +0300 Subject: [PATCH 38/69] fix: Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 39804491..a5e3a601 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,4 @@ jsdocs/ # Generated code lib/ +!test/lib/ From 6f7706aa6191e7f3f03ee2d3ec4198e5ce76fb73 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 27 Aug 2024 15:48:55 +0300 Subject: [PATCH 39/69] fix: Make tests work --- src/adapters/AbstractAdapter.ts | 2 +- src/utils/tsUtils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/adapters/AbstractAdapter.ts b/src/adapters/AbstractAdapter.ts index 2a395f0c..63484a11 100644 --- a/src/adapters/AbstractAdapter.ts +++ b/src/adapters/AbstractAdapter.ts @@ -234,7 +234,7 @@ class AbstractAdapter extends AbstractReaderWriter { source: resource._source, } as Resource_Options; - if (resource._stream) { + if (resource._stream && resource._getBufferFromStream) { options.buffer = await resource._getBufferFromStream(); } else if (resource._createStream) { options.createStream = resource._createStream; diff --git a/src/utils/tsUtils.ts b/src/utils/tsUtils.ts index c54c2115..7dcbd8d0 100644 --- a/src/utils/tsUtils.ts +++ b/src/utils/tsUtils.ts @@ -7,5 +7,5 @@ export function isString(testString: unknown): testString is string { export function isMigratedResource(resource: unknown): resource is Resource { // Check if its a fs/Resource v3, function 'hasProject' was // introduced with v3 therefore take it as the indicator - return !!resource && !!Object.hasOwnProperty.call(resource, "hasProject"); + return !!resource && typeof resource === "object" && ("hasProject" in resource); } From 825976d07d5079d1396827e3a54624cb4fcde954 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Tue, 27 Aug 2024 17:20:28 +0200 Subject: [PATCH 40/69] refactor(.nycrc.json): Fix indent --- .nycrc.json | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/.nycrc.json b/.nycrc.json index 6e7c217f..1ea00929 100644 --- a/.nycrc.json +++ b/.nycrc.json @@ -3,28 +3,28 @@ "reporter": ["lcov", "text", "text-summary"], "include": ["src/**"], "check-coverage": true, - "statements": 90, - "branches": 90, - "functions": 90, - "lines": 90, - "watermarks": { - "statements": [ - 70, - 90 - ], - "branches": [ - 70, - 90 - ], - "functions": [ - 70, - 90 - ], - "lines": [ - 70, - 90 - ] - }, + "statements": 90, + "branches": 90, + "functions": 90, + "lines": 90, + "watermarks": { + "statements": [ + 70, + 90 + ], + "branches": [ + 70, + 90 + ], + "functions": [ + 70, + 90 + ], + "lines": [ + 70, + 90 + ] + }, "cache": true, "all": true } \ No newline at end of file From 2b34270ad220f1cb912f1b139528c08a059f2b67 Mon Sep 17 00:00:00 2001 From: Max Reichmann Date: Wed, 28 Aug 2024 11:25:29 +0200 Subject: [PATCH 41/69] refactor: Fix some ESLint errors --- package.json | 2 ++ test/lib/AbstractReader.ts | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 6c8bacb2..a3e59084 100644 --- a/package.json +++ b/package.json @@ -139,6 +139,8 @@ "depcheck": "^1.4.7", "docdash": "^2.0.2", "eslint": "^9.9.0", + "eslint-plugin-ava": "^15.0.1", + "eslint-plugin-jsdoc": "^50.2.2", "esmock": "^2.6.7", "globals": "^15.9.0", "jsdoc": "^4.0.3", diff --git a/test/lib/AbstractReader.ts b/test/lib/AbstractReader.ts index 9d2fa0bd..0e9a5b1f 100644 --- a/test/lib/AbstractReader.ts +++ b/test/lib/AbstractReader.ts @@ -14,22 +14,22 @@ test("Incomplete AbstractReader subclass: Abstract functions throw error", (t) = class Dummy extends AbstractReader {} const instance = new Dummy(); - t.throws(() => { - instance._byGlob(); + t.throws(async () => { + await instance._byGlob(); }, { instanceOf: Error, message: "Function '_byGlob' is not implemented", }); - t.throws(() => { - instance._runGlob(); + t.throws(async () => { + await instance._runGlob(); }, { instanceOf: Error, message: "Function '_runGlob' is not implemented", }); - t.throws(() => { - instance._byPath(); + t.throws(async () => { + await instance._byPath(); }, { instanceOf: Error, message: "Function '_byPath' is not implemented", From 1f7ee9b0ca5c4ab0914851152f32a4d45ebffde0 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Wed, 28 Aug 2024 13:50:36 +0200 Subject: [PATCH 42/69] [INTERNAL] TypeScript: Add test/expected to eslint ignore list --- eslint.common.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/eslint.common.config.js b/eslint.common.config.js index 5a020740..bc354835 100644 --- a/eslint.common.config.js +++ b/eslint.common.config.js @@ -18,6 +18,7 @@ export default tseslint.config( // Exclude test files "test/tmp/*", "test/fixtures/*", + "test/expected/*", // Exclude generated code "lib/*", From 28fb2657550885096aa44aba158cce60dc330ec6 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 15:24:56 +0300 Subject: [PATCH 43/69] refactor: Autofix JSDoc findings --- src/AbstractReader.ts | 63 ++++++-------- src/AbstractReaderWriter.ts | 29 +++---- src/DuplexCollection.ts | 38 ++++----- src/ReaderCollection.ts | 33 ++++--- src/ReaderCollectionPrioritized.ts | 37 ++++---- src/Resource.ts | 82 +++++++----------- src/ResourceFacade.ts | 63 +++++--------- src/ResourceTagCollection.ts | 6 +- src/WriterCollection.ts | 40 +++++---- src/adapters/AbstractAdapter.ts | 38 ++++----- src/adapters/FileSystem.ts | 52 ++++++----- src/adapters/Memory.ts | 51 +++++------ src/fsInterface.ts | 17 ++-- src/readers/Filter.ts | 48 +++++------ src/readers/Link.ts | 46 +++++----- src/resourceFactory.ts | 123 ++++++++++++--------------- src/tracing/Trace.ts | 2 - src/tracing/traceSummary.ts | 25 ++++++ src/utils/tsUtils.ts | 8 ++ test/lib/adapters/AbstractAdapter.ts | 2 +- 20 files changed, 368 insertions(+), 435 deletions(-) diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index f24abf49..8c6f2967 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -5,9 +5,6 @@ import {ResourceInterface} from "./Resource.js"; /** * Abstract resource locator implementing the general API for reading resources * - * @abstract - * @public - * @class * @alias @ui5/fs/AbstractReader */ class AbstractReader { @@ -15,8 +12,7 @@ class AbstractReader { /** * The constructor. * - * @public - * @param {string} name Name of the reader. Typically used for tracing purposes + * @param name Name of the reader. Typically used for tracing purposes */ constructor(name?: string) { if (new.target === AbstractReader) { @@ -42,14 +38,13 @@ class AbstractReader { * byGlob("**‏/.library"); * byGlob("/pony/*"); * - * @public - * @param {string|string[]} virPattern glob pattern as string or array of glob patterns for + * @param virPattern glob pattern as string or array of glob patterns for * virtual directory structure - * @param {object} [options] glob options - * @param {boolean} [options.nodir=true] Do not match directories - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + * @param [options] glob options + * @param [options.nodir] Do not match directories + * @returns Promise resolving to list of resources */ - byGlob(virPattern: string, options = {nodir: true}): Promise { + byGlob(virPattern: string | string[], options = {nodir: true}): Promise { const trace = new Trace(virPattern); return this._byGlob(virPattern, options, trace).then(function (result: ResourceInterface[]) { trace.printReport(); @@ -70,13 +65,12 @@ class AbstractReader { /** * Locates resources by matching a given path. * - * @public - * @param {string} virPath Virtual path - * @param {object} [options] Options - * @param {boolean} [options.nodir=true] Do not match directories - * @returns {Promise<@ui5/fs/ResourceInterface>} Promise resolving to a single resource + * @param virPath Virtual path + * @param [options] Options + * @param [options.nodir] Do not match directories + * @returns Promise resolving to a single resource */ - byPath(virPath: string, options = {nodir: true}): Promise { + byPath(virPath: string, options = {nodir: true}) { const trace = new Trace(virPath); return this._byPath(virPath, options, trace).then(function (resource) { trace.printReport(); @@ -87,13 +81,12 @@ class AbstractReader { /** * Locates resources by one or more glob patterns. * - * @abstract - * @protected - * @param {string|string[]} virPattern glob pattern as string or an array of + * @param virPattern glob pattern as string or an array of * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/ResourceInterface[]>} Promise resolving to list of resources + * @param _virPattern + * @param _options glob options + * @param _options.nodir + * @param _trace Trace instance */ _byGlob(_virPattern: string | string[], _options: { @@ -106,12 +99,11 @@ class AbstractReader { /** * Locate resources by matching a single glob pattern. * - * @abstract - * @protected - * @param {string|string[]} pattern glob pattern - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/ResourceInterface[]>} Promise resolving to list of resources + * @param pattern glob pattern + * @param _pattern + * @param _options glob options + * @param _options.nodir + * @param _trace Trace instance */ _runGlob(_pattern: string | string[], _options: {nodir: boolean}, _trace: Trace): Promise { throw new Error("Function '_runGlob' is not implemented"); @@ -120,14 +112,13 @@ class AbstractReader { /** * Locates resources by path. * - * @abstract - * @protected - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/ResourceInterface>} Promise resolving to a single resource + * @param virPath Virtual path + * @param _virPath + * @param _options glob options + * @param _options.nodir + * @param _trace Trace instance */ - _byPath(_virPath: string, _options: object, _trace: Trace): Promise { + _byPath(_virPath: string, _options: {nodir: boolean}, _trace: Trace): Promise { throw new Error("Function '_byPath' is not implemented"); } } diff --git a/src/AbstractReaderWriter.ts b/src/AbstractReaderWriter.ts index 58f97ecb..e918a3bc 100644 --- a/src/AbstractReaderWriter.ts +++ b/src/AbstractReaderWriter.ts @@ -4,18 +4,13 @@ import Resource from "./Resource.js"; /** * Abstract resource locator implementing the general API for reading and writing resources * - * @abstract - * @public - * @class * @alias @ui5/fs/AbstractReaderWriter - * @extends @ui5/fs/AbstractReader */ class AbstractReaderWriter extends AbstractReader { /** * The constructor. * - * @public - * @param {string} name Name of the reader/writer. Typically used for tracing purposes + * @param name Name of the reader/writer. Typically used for tracing purposes */ constructor(name?: string) { if (new.target === AbstractReaderWriter) { @@ -36,20 +31,19 @@ class AbstractReaderWriter extends AbstractReader { /** * Writes the content of a resource to a path. * - * @public - * @param {@ui5/fs/Resource} resource Resource to write - * @param {object} [options] - * @param {boolean} [options.readOnly=false] Whether the resource content shall be written read-only + * @param resource Resource to write + * @param [options] + * @param [options.readOnly] Whether the resource content shall be written read-only * Do not use in conjunction with the drain option. * The written file will be used as the new source of this resources content. * Therefore the written file should not be altered by any means. * Activating this option might improve overall memory consumption. - * @param {boolean} [options.drain=false] Whether the resource content shall be emptied during the write process. + * @param [options.drain] Whether the resource content shall be emptied during the write process. * Do not use in conjunction with the readOnly option. * Activating this option might improve overall memory consumption. * This should be used in cases where this is the last access to the resource. * E.g. the final write of a resource after all processing is finished. - * @returns {Promise} Promise resolving once data has been written + * @returns Promise resolving once data has been written */ write(resource: Resource, options = {drain: false, readOnly: false}): Promise { return this._write(resource, options); @@ -58,13 +52,12 @@ class AbstractReaderWriter extends AbstractReader { /** * Writes the content of a resource to a path. * - * @abstract - * @protected - * @param {@ui5/fs/Resource} resource Resource to write - * @param {object} [options] Write options, see above - * @returns {Promise} Promise resolving once data has been written + * @param _resource Resource to write + * @param [_options] Write options, see above + * @param [_options.drain] + * @param [_options.readOnly] */ - _write(_resource: Resource, _options: object): Promise { + _write(_resource: Resource, _options?: {drain?: boolean; readOnly?: boolean}): Promise { throw new Error("Not implemented"); } } diff --git a/src/DuplexCollection.ts b/src/DuplexCollection.ts index 6a91d11e..85476184 100644 --- a/src/DuplexCollection.ts +++ b/src/DuplexCollection.ts @@ -7,10 +7,7 @@ import Trace from "./tracing/Trace.js"; /** * Wrapper to keep readers and writers together * - * @public - * @class * @alias @ui5/fs/DuplexCollection - * @extends @ui5/fs/AbstractReaderWriter */ class DuplexCollection extends AbstractReaderWriter { _reader: AbstractReader; @@ -20,13 +17,13 @@ class DuplexCollection extends AbstractReaderWriter { /** * The Constructor. * - * @param {object} parameters - * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers - * @param {@ui5/fs/AbstractReaderWriter} parameters.writer + * @param parameters + * @param parameters.reader Single reader or collection of readers + * @param parameters.writer * A ReaderWriter instance which is only used for writing files - * @param {string} [parameters.name=""] The collection name + * @param [parameters.name] The collection name */ - constructor({reader, writer, name = ""}: {reader: AbstractReader; writer: AbstractReaderWriter; name: string}) { + constructor({reader, writer, name = ""}: {reader: AbstractReader; writer: AbstractReaderWriter; name?: string}) { super(name); if (!reader) { @@ -51,12 +48,12 @@ class DuplexCollection extends AbstractReaderWriter { /** * Locates resources by glob. * - * @private - * @param {string|string[]} virPattern glob pattern as string or an array of + * @param virPattern glob pattern as string or an array of * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving with a list of resources + * @param options glob options + * @param options.nodir + * @param trace Trace instance + * @returns Promise resolving with a list of resources */ _byGlob(virPattern: string | string[], options: {nodir: boolean}, trace: Trace) { return this._combo._byGlob(virPattern, options, trace); @@ -65,11 +62,11 @@ class DuplexCollection extends AbstractReaderWriter { /** * Locates resources by path. * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource|null>} + * @param virPath Virtual path + * @param options Options + * @param options.nodir + * @param trace Trace instance + * @returns * Promise resolving to a single resource or null if no resource is found */ _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { @@ -79,9 +76,8 @@ class DuplexCollection extends AbstractReaderWriter { /** * Writes the content of a resource to a path. * - * @private - * @param {@ui5/fs/Resource} resource The Resource to write - * @returns {Promise} Promise resolving once data has been written + * @param resource The Resource to write + * @returns Promise resolving once data has been written */ _write(resource: Resource) { return this._writer.write(resource); diff --git a/src/ReaderCollection.ts b/src/ReaderCollection.ts index 57a104a4..7f3f21a3 100644 --- a/src/ReaderCollection.ts +++ b/src/ReaderCollection.ts @@ -5,38 +5,35 @@ import Trace from "./tracing/Trace.js"; /** * Resource Locator ReaderCollection * - * @public - * @class * @alias @ui5/fs/ReaderCollection - * @extends @ui5/fs/AbstractReader */ class ReaderCollection extends AbstractReader { _readers: AbstractReader[]; /** * The constructor. * - * @param {object} parameters Parameters - * @param {string} parameters.name The collection name - * @param {@ui5/fs/AbstractReader[]} [parameters.readers] + * @param parameters Parameters + * @param parameters.name The collection name + * @param [parameters.readers] * List of resource readers (all tried in parallel). * If none are provided, the collection will never return any results. */ - constructor({name, readers}: {name: string; readers: AbstractReader[]}) { + constructor({name, readers}: {name: string; readers?: AbstractReader[]}) { super(name); // Remove any undefined (empty) readers from array - this._readers = readers.filter(($) => $); + this._readers = readers?.filter(($) => $) ?? []; } /** * Locates resources by glob. * - * @private - * @param {string|string[]} pattern glob pattern as string or an array of + * @param pattern glob pattern as string or an array of * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + * @param options glob options + * @param options.nodir + * @param trace Trace instance + * @returns Promise resolving to list of resources */ _byGlob(pattern: string | string[], options: {nodir: boolean}, trace: Trace) { return Promise.all(this._readers.map(function (resourceLocator) { @@ -50,11 +47,11 @@ class ReaderCollection extends AbstractReader { /** * Locates resources by path. * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource|null>} + * @param virPath Virtual path + * @param options Options + * @param options.nodir + * @param trace Trace instance + * @returns * Promise resolving to a single resource or null if no resource is found */ _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { diff --git a/src/ReaderCollectionPrioritized.ts b/src/ReaderCollectionPrioritized.ts index 50ba9f8c..49b19bd3 100644 --- a/src/ReaderCollectionPrioritized.ts +++ b/src/ReaderCollectionPrioritized.ts @@ -1,14 +1,11 @@ import AbstractReader from "./AbstractReader.js"; -import Resource from "./Resource.js"; +import Resource, { ResourceInterface } from "./Resource.js"; import Trace from "./tracing/Trace.js"; /** * Prioritized Resource Locator Collection * - * @public - * @class * @alias @ui5/fs/ReaderCollectionPrioritized - * @extends @ui5/fs/AbstractReader */ class ReaderCollectionPrioritized extends AbstractReader { _readers: AbstractReader[]; @@ -16,28 +13,28 @@ class ReaderCollectionPrioritized extends AbstractReader { /** * The constructor. * - * @param {object} parameters - * @param {string} parameters.name The collection name - * @param {@ui5/fs/AbstractReader[]} [parameters.readers] + * @param parameters + * @param parameters.name The collection name + * @param [parameters.readers] * Prioritized list of resource readers (tried in the order provided). * If none are provided, the collection will never return any results. */ - constructor({readers, name}: {readers: AbstractReader[]; name: string}) { + constructor({readers, name}: {readers?: AbstractReader[]; name: string}) { super(name); // Remove any undefined (empty) readers from array - this._readers = readers.filter(($) => $); + this._readers = readers?.filter(($) => $) ?? []; } /** * Locates resources by glob. * - * @private - * @param {string|string[]} pattern glob pattern as string or an array of + * @param pattern glob pattern as string or an array of * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + * @param options glob options + * @param options.nodir + * @param trace Trace instance + * @returns Promise resolving to list of resources */ _byGlob(pattern: string | string[], options: {nodir: boolean}, trace: Trace) { return Promise.all(this._readers.map(function (resourceLocator) { @@ -67,11 +64,11 @@ class ReaderCollectionPrioritized extends AbstractReader { /** * Locates resources by path. * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource|null>} + * @param virPath Virtual path + * @param options Options + * @param options.nodir + * @param trace Trace instance + * @returns * Promise resolving to a single resource or null if no resource is found */ _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { @@ -81,7 +78,7 @@ class ReaderCollectionPrioritized extends AbstractReader { return Promise.resolve(null); } return this._readers[i]._byPath(virPath, options, trace) - .then((resource: Resource | null): Resource | Promise => { + .then((resource: ResourceInterface | null): ResourceInterface | Promise => { if (resource) { resource.pushCollection(this._name!); return resource; diff --git a/src/Resource.ts b/src/Resource.ts index 6c5d53b2..7a9a08ae 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -18,8 +18,6 @@ enum ALLOWED_SOURCE_METADATA_KEYS { /** * Function for dynamic creation of content streams * - * @public - * @callback @ui5/fs/Resource~createStream * @returns {stream.Readable} A readable stream of a resources content */ export type Resource_CreateReadableStream = () => stream.Readable; @@ -87,8 +85,6 @@ export interface ResourceInterface { /** * Resource. UI5 Tooling specific representation of a file's content and metadata * - * @public - * @class * @alias @ui5/fs/Resource */ class Resource implements ResourceInterface { @@ -108,23 +104,22 @@ class Resource implements ResourceInterface { /** * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.path Absolute virtual path of the resource - * @param {fs.Stats|object} [parameters.statInfo] File information. Instance of + * @param parameters Parameters + * @param parameters.path Absolute virtual path of the resource + * @param [parameters.statInfo] File information. Instance of * [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} or similar object - * @param {Buffer} [parameters.buffer] Content of this resources as a Buffer instance + * @param [parameters.buffer] Content of this resources as a Buffer instance * (cannot be used in conjunction with parameters string, stream or createStream) - * @param {string} [parameters.string] Content of this resources as a string + * @param [parameters.string] Content of this resources as a string * (cannot be used in conjunction with parameters buffer, stream or createStream) - * @param {Stream} [parameters.stream] Readable stream of the content of this resource + * @param [parameters.stream] Readable stream of the content of this resource * (cannot be used in conjunction with parameters buffer, string or createStream) - * @param {@ui5/fs/Resource~createStream} [parameters.createStream] Function callback that returns a readable + * @param [parameters.createStream] Function callback that returns a readable * stream of the content of this resource (cannot be used in conjunction with parameters buffer, * string or stream). * In some cases this is the most memory-efficient way to supply resource content - * @param {@ui5/project/specifications/Project} [parameters.project] Project this resource is associated with - * @param {object} [parameters.sourceMetadata] Source metadata for UI5 Tooling internal use. + * @param [parameters.project] Project this resource is associated with + * @param [parameters.sourceMetadata] Source metadata for UI5 Tooling internal use. * Some information may be set by an adapter to store information for later retrieval. Also keeps track of whether * a resource content has been modified since it has been read from a source */ @@ -212,8 +207,7 @@ class Resource implements ResourceInterface { /** * Gets a buffer with the resource content. * - * @public - * @returns {Promise} Promise resolving with a buffer of the resource content. + * @returns Promise resolving with a buffer of the resource content. */ async getBuffer(): Promise { if (this.#contentDrained) { @@ -233,8 +227,7 @@ class Resource implements ResourceInterface { /** * Sets a Buffer as content. * - * @public - * @param {Buffer} buffer Buffer instance + * @param buffer Buffer instance */ setBuffer(buffer: Buffer) { this.#sourceMetadata.contentModified = true; @@ -256,8 +249,7 @@ class Resource implements ResourceInterface { /** * Gets a string with the resource content. * - * @public - * @returns {Promise} Promise resolving with the resource content. + * @returns Promise resolving with the resource content. */ getString(): Promise { if (this.#contentDrained) { @@ -271,8 +263,7 @@ class Resource implements ResourceInterface { /** * Sets a String as content * - * @public - * @param {string} string Resource content + * @param string Resource content */ setString(string: string) { this.setBuffer(Buffer.from(string, "utf8")); @@ -286,8 +277,7 @@ class Resource implements ResourceInterface { * or [setString]{@link @ui5/fs/Resource#setString}). This * is to prevent consumers from accessing drained streams. * - * @public - * @returns {stream.Readable} Readable stream for the resource content. + * @returns Readable stream for the resource content. */ getStream(): stream.Readable { if (this.#contentDrained) { @@ -321,8 +311,7 @@ class Resource implements ResourceInterface { /** * Sets a readable stream as content. * - * @public - * @param {stream.Readable|@ui5/fs/Resource~createStream} stream Readable stream of the resource content or + * @param stream Readable stream of the resource content or callback for dynamic creation of a readable stream */ setStream(stream: stream.Readable | Resource_CreateReadableStream) { @@ -347,8 +336,7 @@ class Resource implements ResourceInterface { /** * Gets the virtual resources path * - * @public - * @returns {string} Virtual path of the resource + * @returns Virtual path of the resource */ getPath(): string { return this.#path ?? ""; @@ -357,8 +345,7 @@ class Resource implements ResourceInterface { /** * Sets the virtual resources path * - * @public - * @param {string} path Absolute virtual path of the resource + * @param path Absolute virtual path of the resource */ setPath(path: string) { path = posixPath.normalize(path); @@ -372,8 +359,7 @@ class Resource implements ResourceInterface { /** * Gets the resource name * - * @public - * @returns {string} Name of the resource + * @returns Name of the resource */ getName(): string { return this.#name; @@ -385,8 +371,7 @@ class Resource implements ResourceInterface { * Also, depending on the used adapter, some fields might be missing which would be present for a * [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} instance. * - * @public - * @returns {fs.Stats|object} Instance of [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} + * @returns Instance of [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} * or similar object */ getStatInfo(): Partial { @@ -397,7 +382,7 @@ class Resource implements ResourceInterface { * Size in bytes allocated by the underlying buffer. * * @see {TypedArray#byteLength} - * @returns {Promise} size in bytes, 0 if there is no content yet + * @returns size in bytes, 0 if there is no content yet */ async getSize(): Promise { // if resource does not have any content it should have 0 bytes @@ -411,7 +396,7 @@ class Resource implements ResourceInterface { /** * Adds a resource collection name that was involved in locating this resource. * - * @param {string} name Resource collection name + * @param name Resource collection name */ pushCollection(name: string) { this.#collections.push(name); @@ -420,8 +405,7 @@ class Resource implements ResourceInterface { /** * Returns a clone of the resource. The clones content is independent from that of the original resource * - * @public - * @returns {Promise<@ui5/fs/Resource>} Promise resolving with the clone + * @returns Promise resolving with the clone */ async clone(): Promise { const options = await this.#getCloneOptions(); @@ -456,8 +440,7 @@ class Resource implements ResourceInterface { * [MiddlewareUtil]{@link module:@ui5/server.middleware.MiddlewareUtil}, which will * return a Specification Version-compatible Project interface. * - * @public - * @returns {@ui5/project/specifications/Project|undefined} Project this resource is associated with + * @returns Project this resource is associated with */ getProject(): Project | undefined { return this.#project; @@ -466,8 +449,7 @@ class Resource implements ResourceInterface { /** * Assign a project to the resource * - * @public - * @param {@ui5/project/specifications/Project} project Project this resource is associated with + * @param project Project this resource is associated with */ setProject(project: Project) { if (this.#project) { @@ -480,8 +462,7 @@ class Resource implements ResourceInterface { /** * Check whether a project has been assigned to the resource * - * @public - * @returns {boolean} True if the resource is associated with a project + * @returns True if the resource is associated with a project */ hasProject(): boolean { return !!this.#project; @@ -490,8 +471,7 @@ class Resource implements ResourceInterface { /** * Check whether the content of this resource has been changed during its life cycle * - * @public - * @returns {boolean} True if the resource's content has been changed + * @returns True if the resource's content has been changed */ isModified(): boolean { return this.#isModified; @@ -500,7 +480,7 @@ class Resource implements ResourceInterface { /** * Tracing: Get tree for printing out trace * - * @returns {object} Trace tree + * @returns Trace tree */ getPathTree(): Tree { const tree = Object.create(null) as Tree; @@ -518,7 +498,7 @@ class Resource implements ResourceInterface { * Returns source metadata which may contain information specific to the adapter that created the resource * Typically set by an adapter to store information for later retrieval. * - * @returns {object} + * @returns */ getSourceMetadata(): Resource_sourceMetadata { return this.#sourceMetadata; @@ -527,8 +507,7 @@ class Resource implements ResourceInterface { /** * Returns the content as stream. * - * @private - * @returns {stream.Readable} Readable stream + * @returns Readable stream */ #getStream(): stream.Readable { if (this.#streamDrained) { @@ -544,8 +523,7 @@ class Resource implements ResourceInterface { /** * Converts the buffer into a stream. * - * @private - * @returns {Promise} Promise resolving with buffer. + * @returns Promise resolving with buffer. */ #getBufferFromStream(): Promise { if (this.#buffering) { // Prevent simultaneous buffering, causing unexpected access to drained stream diff --git a/src/ResourceFacade.ts b/src/ResourceFacade.ts index 81f56572..ff6bb0f8 100644 --- a/src/ResourceFacade.ts +++ b/src/ResourceFacade.ts @@ -8,8 +8,6 @@ import {Project} from "@ui5/project/specifications/Project"; /** * A {@link @ui5/fs/Resource Resource} with a different path than it's original * - * @public - * @class * @alias @ui5/fs/ResourceFacade */ class ResourceFacade implements ResourceInterface { @@ -19,9 +17,8 @@ class ResourceFacade implements ResourceInterface { /** * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.path Virtual path of the facade resource + * @param parameters Parameters + * @param parameters.path Virtual path of the facade resource * @param parameters.resource Resource to conceal */ constructor({path, resource}: {path: string; resource: ResourceInterface}) { @@ -43,8 +40,7 @@ class ResourceFacade implements ResourceInterface { /** * Gets the resources path * - * @public - * @returns {string} (Virtual) path of the resource + * @returns (Virtual) path of the resource */ getPath() { return this.#path; @@ -53,8 +49,7 @@ class ResourceFacade implements ResourceInterface { /** * Gets the resource name * - * @public - * @returns {string} Name of the resource + * @returns Name of the resource */ getName() { return this.#name; @@ -63,8 +58,8 @@ class ResourceFacade implements ResourceInterface { /** * Sets the resources path * - * @public - * @param {string} path (Virtual) path of the resource + * @param _path + * @param path (Virtual) path of the resource */ setPath(_path: string) { throw new Error(`The path of a ResourceFacade can't be changed`); @@ -74,8 +69,7 @@ class ResourceFacade implements ResourceInterface { * Returns a clone of the resource. The clones content is independent from that of the original resource. * A ResourceFacade becomes a Resource * - * @public - * @returns {Promise<@ui5/fs/Resource>} Promise resolving with the clone + * @returns Promise resolving with the clone */ async clone() { // Cloning resolves the facade @@ -92,8 +86,7 @@ class ResourceFacade implements ResourceInterface { /** * Gets a buffer with the resource content. * - * @public - * @returns {Promise} Promise resolving with a buffer of the resource content. + * @returns Promise resolving with a buffer of the resource content. */ async getBuffer() { return this.#resource.getBuffer(); @@ -102,8 +95,7 @@ class ResourceFacade implements ResourceInterface { /** * Sets a Buffer as content. * - * @public - * @param {Buffer} buffer Buffer instance + * @param buffer Buffer instance */ setBuffer(buffer: Buffer) { return this.#resource.setBuffer(buffer); @@ -112,8 +104,7 @@ class ResourceFacade implements ResourceInterface { /** * Gets a string with the resource content. * - * @public - * @returns {Promise} Promise resolving with the resource content. + * @returns Promise resolving with the resource content. */ getString() { return this.#resource.getString(); @@ -122,8 +113,7 @@ class ResourceFacade implements ResourceInterface { /** * Sets a String as content * - * @public - * @param {string} string Resource content + * @param string Resource content */ setString(string: string) { return this.#resource.setString(string); @@ -137,8 +127,7 @@ class ResourceFacade implements ResourceInterface { * or [setString]{@link @ui5/fs/Resource#setString}). This * is to prevent consumers from accessing drained streams. * - * @public - * @returns {stream.Readable} Readable stream for the resource content. + * @returns Readable stream for the resource content. */ getStream() { return this.#resource.getStream(); @@ -147,8 +136,7 @@ class ResourceFacade implements ResourceInterface { /** * Sets a readable stream as content. * - * @public - * @param {stream.Readable|@ui5/fs/Resource~createStream} stream Readable stream of the resource content or + * @param stream Readable stream of the resource content or callback for dynamic creation of a readable stream */ setStream(stream: stream.Readable | Resource_CreateReadableStream) { @@ -161,8 +149,7 @@ class ResourceFacade implements ResourceInterface { * Also, depending on the used adapter, some fields might be missing which would be present for a * [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} instance. * - * @public - * @returns {fs.Stats|object} Instance of [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} + * @returns Instance of [fs.Stats]{@link https://nodejs.org/api/fs.html#fs_class_fs_stats} * or similar object */ getStatInfo() { @@ -173,7 +160,7 @@ class ResourceFacade implements ResourceInterface { * Size in bytes allocated by the underlying buffer. * * @see {TypedArray#byteLength} - * @returns {Promise} size in bytes, 0 if there is no content yet + * @returns size in bytes, 0 if there is no content yet */ getSize() { return this.#resource.getSize(); @@ -182,7 +169,7 @@ class ResourceFacade implements ResourceInterface { /** * Adds a resource collection name that was involved in locating this resource. * - * @param {string} name Resource collection name + * @param name Resource collection name */ pushCollection(name: string) { return this.#resource.pushCollection(name); @@ -191,7 +178,7 @@ class ResourceFacade implements ResourceInterface { /** * Tracing: Get tree for printing out trace * - * @returns {object} Trace tree + * @returns Trace tree */ getPathTree() { return this.#resource.getPathTree(); @@ -207,8 +194,7 @@ class ResourceFacade implements ResourceInterface { * [MiddlewareUtil]{@link module:@ui5/server.middleware.MiddlewareUtil}, which will * return a Specification Version-compatible Project interface. * - * @public - * @returns {@ui5/project/specifications/Project} Project this resource is associated with + * @returns Project this resource is associated with */ getProject() { return this.#resource.getProject(); @@ -217,8 +203,7 @@ class ResourceFacade implements ResourceInterface { /** * Assign a project to the resource * - * @public - * @param {@ui5/project/specifications/Project} project Project this resource is associated with + * @param project Project this resource is associated with */ setProject(project: Project) { return this.#resource.setProject(project); @@ -227,8 +212,7 @@ class ResourceFacade implements ResourceInterface { /** * Check whether a project has been assigned to the resource * - * @public - * @returns {boolean} True if the resource is associated with a project + * @returns True if the resource is associated with a project */ hasProject() { return this.#resource.hasProject(); @@ -237,8 +221,7 @@ class ResourceFacade implements ResourceInterface { /** * Check whether the content of this resource has been changed during its life cycle * - * @public - * @returns {boolean} True if the resource's content has been changed + * @returns True if the resource's content has been changed */ isModified() { return this.#resource.isModified(); @@ -248,7 +231,7 @@ class ResourceFacade implements ResourceInterface { * Returns source metadata if any where provided during the creation of this resource. * Typically set by an adapter to store information for later retrieval. * - * @returns {object|null} + * @returns */ getSourceMetadata() { return this.#resource.getSourceMetadata(); @@ -257,7 +240,7 @@ class ResourceFacade implements ResourceInterface { /** * Returns the resource concealed by this facade * - * @returns {@ui5/fs/Resource} + * @returns */ getConcealedResource() { return this.#resource; diff --git a/src/ResourceTagCollection.ts b/src/ResourceTagCollection.ts index 48850b04..3bfce49e 100644 --- a/src/ResourceTagCollection.ts +++ b/src/ResourceTagCollection.ts @@ -6,6 +6,10 @@ import ResourceFacade from "./ResourceFacade.js"; interface PathTagsInterface { [key: string]: string | number | boolean | undefined | PathTagsInterface; }; +/** + * + * @param elem + */ export function isPathTagsInterface(elem: unknown): elem is PathTagsInterface { return typeof elem === "object"; } @@ -13,8 +17,6 @@ export function isPathTagsInterface(elem: unknown): elem is PathTagsInterface { /** * A ResourceTagCollection * - * @private - * @class * @alias @ui5/fs/internal/ResourceTagCollection */ class ResourceTagCollection { diff --git a/src/WriterCollection.ts b/src/WriterCollection.ts index f6043410..81d42372 100644 --- a/src/WriterCollection.ts +++ b/src/WriterCollection.ts @@ -7,10 +7,7 @@ import Resource from "./Resource.js"; /** * Resource Locator WriterCollection * - * @public - * @class * @alias @ui5/fs/WriterCollection - * @extends @ui5/fs/AbstractReaderWriter */ class WriterCollection extends AbstractReaderWriter { _basePathRegex: string; @@ -20,9 +17,9 @@ class WriterCollection extends AbstractReaderWriter { /** * The constructor. * - * @param {object} parameters Parameters - * @param {string} parameters.name The collection name - * @param {object.} parameters.writerMapping + * @param parameters Parameters + * @param parameters.name The collection name + * @param parameters.writerMapping * Mapping of virtual base paths to writers. Path are matched greedy * * @example @@ -74,12 +71,12 @@ class WriterCollection extends AbstractReaderWriter { /** * Locates resources by glob. * - * @private - * @param {string|string[]} pattern glob pattern as string or an array of + * @param pattern glob pattern as string or an array of * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + * @param options glob options + * @param options.nodir + * @param trace Trace instance + * @returns Promise resolving to list of resources */ _byGlob(pattern: string | string[], options: {nodir: boolean}, trace: Trace) { return this._readerCollection._byGlob(pattern, options, trace); @@ -88,11 +85,11 @@ class WriterCollection extends AbstractReaderWriter { /** * Locates resources by path. * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + * @param virPath Virtual path + * @param options Options + * @param options.nodir + * @param trace Trace instance + * @returns Promise resolving to a single resource */ _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { return this._readerCollection._byPath(virPath, options, trace); @@ -101,12 +98,13 @@ class WriterCollection extends AbstractReaderWriter { /** * Writes the content of a resource to a path. * - * @private - * @param {@ui5/fs/Resource} resource The Resource to write - * @param {object} [options] Write options, see above - * @returns {Promise} Promise resolving once data has been written + * @param resource The Resource to write + * @param [options] Write options, see above + * @param [options.drain] + * @param [options.readOnly] + * @returns Promise resolving once data has been written */ - _write(resource: Resource, options: object) { + _write(resource: Resource, options?: {drain?: boolean; readOnly?: boolean}) { const resourcePath = resource.getPath(); const basePathMatch = resourcePath.match(this._basePathRegex); diff --git a/src/adapters/AbstractAdapter.ts b/src/adapters/AbstractAdapter.ts index 63484a11..b0d726a4 100644 --- a/src/adapters/AbstractAdapter.ts +++ b/src/adapters/AbstractAdapter.ts @@ -12,11 +12,7 @@ import {isMigratedResource} from "../utils/tsUtils.js"; /** * Abstract Resource Adapter * - * @abstract - * @public - * @class * @alias @ui5/fs/adapters/AbstractAdapter - * @extends @ui5/fs/AbstractReaderWriter */ class AbstractAdapter extends AbstractReaderWriter { _virBasePath: string; @@ -28,12 +24,11 @@ class AbstractAdapter extends AbstractReaderWriter { /** * The constructor * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.virBasePath + * @param parameters Parameters + * @param parameters.virBasePath * Virtual base path. Must be absolute, POSIX-style, and must end with a slash - * @param {string[]} [parameters.excludes] List of glob patterns to exclude - * @param {object} [parameters.project] Experimental, internal parameter. Do not use + * @param [parameters.excludes] List of glob patterns to exclude + * @param [parameters.project] Experimental, internal parameter. Do not use */ constructor({virBasePath, excludes = [], project}: {virBasePath: string; excludes?: string[]; project?: Project}) { @@ -62,14 +57,12 @@ class AbstractAdapter extends AbstractReaderWriter { /** * Locates resources by glob. * - * @abstract - * @private - * @param {string|string[]} virPattern glob pattern as string or an array of + * @param virPattern glob pattern as string or an array of * glob patterns for virtual directory structure - * @param {object} [options={}] glob options - * @param {boolean} [options.nodir=true] Do not match directories - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + * @param [options] glob options + * @param [options.nodir] Do not match directories + * @param trace Trace instance + * @returns Promise resolving to list of resources */ async _byGlob(virPattern: string | string[], options = {nodir: true}, trace: Trace): Promise { const excludes = this._excludesNegated; @@ -113,8 +106,8 @@ class AbstractAdapter extends AbstractReaderWriter { /** * Validate if virtual path should be excluded * - * @param {string[]} virPath Virtual Path - * @returns {boolean} True if path is excluded, otherwise false + * @param virPath Virtual Path + * @returns True if path is excluded, otherwise false */ _isPathExcluded(virPath: string[]) { return micromatch(virPath, this._excludes).length > 0; @@ -125,8 +118,8 @@ class AbstractAdapter extends AbstractReaderWriter { * This means that it either starts with the virtual base path of the adapter * or equals the base directory (base path without a trailing slash) * - * @param {string} virPath Virtual Path - * @returns {boolean} True if path should be handled + * @param virPath Virtual Path + * @returns True if path should be handled */ _isPathHandled(virPath: string) { // Check whether path starts with base path, or equals base directory @@ -136,9 +129,8 @@ class AbstractAdapter extends AbstractReaderWriter { /** * Normalizes virtual glob patterns. * - * @private - * @param {string} virPattern glob pattern for virtual directory structure - * @returns {string[]} A list of normalized glob patterns + * @param virPattern glob pattern for virtual directory structure + * @returns A list of normalized glob patterns */ _normalizePattern(virPattern: string) { const mm = new minimatch.Minimatch(virPattern); diff --git a/src/adapters/FileSystem.ts b/src/adapters/FileSystem.ts index db5935f6..8155ae7d 100644 --- a/src/adapters/FileSystem.ts +++ b/src/adapters/FileSystem.ts @@ -19,10 +19,7 @@ const ADAPTER_NAME = "FileSystem"; /** * File system resource adapter * - * @public - * @class * @alias @ui5/fs/adapters/FileSystem - * @extends @ui5/fs/adapters/AbstractAdapter */ class FileSystem extends AbstractAdapter { _fsBasePath: string; @@ -32,18 +29,18 @@ class FileSystem extends AbstractAdapter { /** * The Constructor. * - * @param {object} parameters Parameters - * @param {string} parameters.virBasePath + * @param parameters Parameters + * @param parameters.virBasePath * Virtual base path. Must be absolute, POSIX-style, and must end with a slash - * @param {string} parameters.fsBasePath + * @param parameters.fsBasePath * File System base path. Must be absolute and must use platform-specific path segment separators - * @param {string[]} [parameters.excludes] List of glob patterns to exclude - * @param {object} [parameters.useGitignore=false] + * @param [parameters.excludes] List of glob patterns to exclude + * @param [parameters.useGitignore] * Whether to apply any excludes defined in an optional .gitignore in the given fsBasePath directory - * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) + * @param [parameters.project] Project this adapter belongs to (if any) */ constructor({virBasePath, project, fsBasePath, excludes, useGitignore = false}: - {virBasePath: string; project: Project; fsBasePath: string; excludes: string[]; useGitignore: boolean} + {virBasePath: string; project?: Project; fsBasePath: string; excludes?: string[]; useGitignore?: boolean} ) { super({virBasePath, project, excludes}); @@ -60,12 +57,11 @@ class FileSystem extends AbstractAdapter { /** * Locate resources by glob. * - * @private - * @param {Array} patterns Array of glob patterns - * @param {object} [options={}] glob options - * @param {boolean} [options.nodir=true] Do not match directories - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + * @param patterns Array of glob patterns + * @param [options] glob options + * @param [options.nodir] Do not match directories + * @param trace Trace instance + * @returns Promise resolving to list of resources */ async _runGlob(patterns: string[], options = {nodir: true}, trace: Trace) { const opt = { @@ -154,11 +150,11 @@ class FileSystem extends AbstractAdapter { /** * Locate a resource by path. * - * @private - * @param {string} virPath Absolute virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource or null if not found + * @param virPath Absolute virtual path + * @param options Options + * @param options.nodir + * @param trace Trace instance + * @returns Promise resolving to a single resource or null if not found */ async _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { const relPath = this._resolveVirtualPathToBase(virPath); @@ -234,22 +230,22 @@ class FileSystem extends AbstractAdapter { /** * Writes the content of a resource to a path. * - * @private - * @param {@ui5/fs/Resource} resource Resource to write - * @param {object} [options] - * @param {boolean} [options.readOnly] Whether the resource content shall be written read-only + * @param resource Resource to write + * @param [options] + * @param [options.readOnly] Whether the resource content shall be written read-only * Do not use in conjunction with the drain option. * The written file will be used as the new source of this resources content. * Therefore the written file should not be altered by any means. * Activating this option might improve overall memory consumption. - * @param {boolean} [options.drain] Whether the resource content shall be emptied during the write process. + * @param [options.drain] Whether the resource content shall be emptied during the write process. * Do not use in conjunction with the readOnly option. * Activating this option might improve overall memory consumption. * This should be used in cases where this is the last access to the resource. + * @param anyResource * E.g. the final write of a resource after all processing is finished. - * @returns {Promise} Promise resolving once data has been written + * @returns Promise resolving once data has been written */ - async _write(anyResource: LegacyResource | Resource, {drain, readOnly}: {drain: boolean; readOnly: boolean}) { + async _write(anyResource: LegacyResource | Resource, {drain, readOnly}: {drain?: boolean; readOnly?: boolean}) { const potentialResourceP = this._migrateResource(anyResource); let resource: Resource; if (potentialResourceP instanceof Promise) { diff --git a/src/adapters/Memory.ts b/src/adapters/Memory.ts index 2caf6ea5..7739b378 100644 --- a/src/adapters/Memory.ts +++ b/src/adapters/Memory.ts @@ -3,7 +3,7 @@ const log = getLogger("resources:adapters:Memory"); import micromatch from "micromatch"; import AbstractAdapter from "./AbstractAdapter.js"; import {Project} from "@ui5/project/specifications/Project"; -import Resource, {LegacyResource} from "../Resource.js"; +import Resource, {LegacyResource, ResourceInterface} from "../Resource.js"; import Trace from "../tracing/Trace.js"; const ADAPTER_NAME = "Memory"; @@ -11,10 +11,7 @@ const ADAPTER_NAME = "Memory"; /** * Virtual resource Adapter * - * @public - * @class * @alias @ui5/fs/adapters/Memory - * @extends @ui5/fs/adapters/AbstractAdapter */ class Memory extends AbstractAdapter { _virFiles: Record; @@ -23,12 +20,11 @@ class Memory extends AbstractAdapter { /** * The constructor. * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.virBasePath + * @param parameters Parameters + * @param parameters.virBasePath * Virtual base path. Must be absolute, POSIX-style, and must end with a slash - * @param {string[]} [parameters.excludes] List of glob patterns to exclude - * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) + * @param [parameters.excludes] List of glob patterns to exclude + * @param [parameters.project] Project this adapter belongs to (if any) */ constructor({virBasePath, project, excludes}: {virBasePath: string; project?: Project; excludes?: string[]}) { super({virBasePath, project, excludes}); @@ -39,12 +35,11 @@ class Memory extends AbstractAdapter { /** * Matches and returns resources from a given map (either _virFiles or _virDirs). * - * @private - * @param {string[]} patterns - * @param {object} resourceMap - * @returns {Promise} + * @param patterns + * @param resourceMap + * @returns */ - async _matchPatterns(patterns: string[], resourceMap: Record): Promise { + async _matchPatterns(patterns: string[], resourceMap: Record): Promise { const resourcePaths = Object.keys(resourceMap); const matchedPaths = micromatch(resourcePaths, patterns, { dot: true, @@ -68,12 +63,12 @@ class Memory extends AbstractAdapter { /** * Locate resources by glob. * - * @private - * @param {Array} patterns array of glob patterns - * @param {object} [options={}] glob options - * @param {boolean} [options.nodir=true] Do not match directories - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + * @param patterns array of glob patterns + * @param [options] glob options + * @param [options.nodir] Do not match directories + * @param _trace + * @param trace Trace instance + * @returns Promise resolving to list of resources */ async _runGlob(patterns: string[], options = {nodir: true}, _trace: Trace) { if (patterns[0] === "" && !options.nodir) { // Match virtual root directory @@ -106,11 +101,11 @@ class Memory extends AbstractAdapter { /** * Locates resources by path. * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing.Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + * @param virPath Virtual path + * @param options Options + * @param options.nodir + * @param trace Trace instance + * @returns Promise resolving to a single resource */ async _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { const relPath = this._resolveVirtualPathToBase(virPath); @@ -132,9 +127,9 @@ class Memory extends AbstractAdapter { /** * Writes the content of a resource to a path. * - * @private - * @param {@ui5/fs/Resource} resource The Resource to write - * @returns {Promise} Promise resolving once data has been written + * @param anyResource + * @param resource The Resource to write + * @returns Promise resolving once data has been written */ async _write(anyResource: Resource | LegacyResource) { const migratedResource = this._migrateResource(anyResource); diff --git a/src/fsInterface.ts b/src/fsInterface.ts index 95aed004..4c5f6db3 100644 --- a/src/fsInterface.ts +++ b/src/fsInterface.ts @@ -2,6 +2,10 @@ import AbstractReader from "./AbstractReader.js"; import type * as fs from "node:fs"; import {Buffer} from "node:buffer"; +/** + * + * @param inputPath Path to convert to POSIX + */ function toPosix(inputPath: string) { return inputPath.replace(/\\/g, "/"); } @@ -16,10 +20,8 @@ type Readdir_Callback = (err: Error | null, files?: string[]) => void; type Mkdir_Callback = (err?: Error | null) => void; /** - * @public - * @module @ui5/fs/fsInterface */ -interface File_System { +interface File_System_Interface { readFile: (fsPath: string, options: Read_File_Options, callback: Read_File_Callback) => void; stat: (fsPath: string, callback: Stat_Callback) => void; readdir: (fsPath: string, callback: Readdir_Callback) => void; @@ -29,19 +31,16 @@ interface File_System { /** * Wraps readers to access them through a [Node.js fs]{@link https://nodejs.org/api/fs.html} styled interface. * - * @public - * @function default - * @static - * @param {@ui5/fs/AbstractReader} reader Resource Reader or Collection + * @param reader Resource Reader or Collection * - * @returns {object} Object with [Node.js fs]{@link https://nodejs.org/api/fs.html} styled functions + * @returns Object with [Node.js fs]{@link https://nodejs.org/api/fs.html} styled functions * [readFile]{@link https://nodejs.org/api/fs.html#fs_fs_readfile_path_options_callback}, * [stat]{@link https://nodejs.org/api/fs.html#fs_fs_stat_path_options_callback}, * [readdir]{@link https://nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback} and * [mkdir]{@link https://nodejs.org/api/fs.html#fs_fs_mkdir_path_options_callback} */ function fsInterface(reader: AbstractReader) { - const fileSystem: File_System = { + const fileSystem: File_System_Interface = { readFile(fsPath, options, callback) { if (typeof options === "function") { callback = options; diff --git a/src/readers/Filter.ts b/src/readers/Filter.ts index 55344e2a..cb3db87c 100644 --- a/src/readers/Filter.ts +++ b/src/readers/Filter.ts @@ -2,39 +2,35 @@ import AbstractReader from "../AbstractReader.js"; import {ResourceInterface} from "../Resource.js"; import Trace from "../tracing/Trace.js"; +/** + * Filter callback + * + * @param resource Resource to test + * @returns Whether to keep the resource + */ +type Filter_Callback = (resource: ResourceInterface) => boolean; + export interface Filter_Params { reader: AbstractReader; - callback: (resource: ResourceInterface) => boolean; + callback: Filter_Callback; }; /** * A reader that allows dynamic filtering of resources passed through it * - * @public - * @class * @alias @ui5/fs/readers/Filter - * @extends @ui5/fs/AbstractReader */ class Filter extends AbstractReader { _reader: AbstractReader; _callback: (resource: ResourceInterface) => boolean; - /** - * Filter callback - * - * @public - * @callback @ui5/fs/readers/Filter~callback - * @param {@ui5/fs/Resource} resource Resource to test - * @returns {boolean} Whether to keep the resource - */ /** * Constructor * - * @public - * @param {object} parameters Parameters - * @param {@ui5/fs/AbstractReader} parameters.reader The resource reader or collection to wrap - * @param {@ui5/fs/readers/Filter~callback} parameters.callback + * @param parameters Parameters + * @param parameters.reader The resource reader or collection to wrap + * @param parameters.callback * Filter function. Will be called for every resource read through this reader. */ constructor({reader, callback}: Filter_Params) { @@ -52,12 +48,12 @@ class Filter extends AbstractReader { /** * Locates resources by glob. * - * @private - * @param {string|string[]} pattern glob pattern as string or an array of + * @param pattern glob pattern as string or an array of * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing/Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + * @param options glob options + * @param options.nodir + * @param trace Trace instance + * @returns Promise resolving to list of resources */ async _byGlob(pattern: string | string[], options: {nodir: boolean}, trace: Trace) { const result = await this._reader._byGlob(pattern, options, trace); @@ -67,11 +63,11 @@ class Filter extends AbstractReader { /** * Locates resources by path. * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing/Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + * @param virPath Virtual path + * @param options Options + * @param options.nodir + * @param trace Trace instance + * @returns Promise resolving to a single resource */ async _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { const result = await this._reader._byPath(virPath, options, trace); diff --git a/src/readers/Link.ts b/src/readers/Link.ts index f1ff3e93..69011b96 100644 --- a/src/readers/Link.ts +++ b/src/readers/Link.ts @@ -5,6 +5,8 @@ import {getLogger} from "@ui5/logger"; const log = getLogger("resources:readers:Link"); import Trace from "../tracing/Trace.js"; +export interface Link_Params {reader: AbstractReader; pathMapping: {linkPath: string; targetPath: string}; + /** * A reader that allows for rewriting paths segments of all resources passed through it. * @@ -22,32 +24,30 @@ import Trace from "../tracing/Trace.js"; * // located at "/resources/my-app-name/Component.js" in the sourceReader * const resource = await linkedReader.byPath("/app/Component.js"); * - * @public - * @class * @alias @ui5/fs/readers/Link - * @extends @ui5/fs/AbstractReader */ class Link extends AbstractReader { _reader: AbstractReader; - _pathMapping: {linkPath: string; targetPath: string}; + /** * Path mapping for a [Link]{@link @ui5/fs/readers/Link} * - * @public - * @typedef {object} @ui5/fs/readers/Link/PathMapping - * @property {string} linkPath Path to match and replace in the requested path or pattern - * @property {string} targetPath Path to use as a replacement in the request for the source reader + * linkPath Path to match and replace in the requested path or pattern + * + * targetPath Path to use as a replacement in the request for the source reader */ + _pathMapping: {linkPath: string; targetPath: string}; /** * Constructor * - * @public - * @param {object} parameters Parameters - * @param {@ui5/fs/AbstractReader} parameters.reader The resource reader or collection to wrap - * @param {@ui5/fs/readers/Link/PathMapping} parameters.pathMapping + * @param parameters Parameters + * @param parameters.reader The resource reader or collection to wrap + * @param parameters.pathMapping + * @param parameters.pathMapping.linkPath + * @param parameters.pathMapping.targetPath */ - constructor({reader, pathMapping}: {reader: AbstractReader; pathMapping: {linkPath: string; targetPath: string}}) { + constructor({reader, pathMapping}: Link_Params) { super(); if (!reader) { throw new Error(`Missing parameter "reader"`); @@ -63,12 +63,12 @@ class Link extends AbstractReader { /** * Locates resources by glob. * - * @private - * @param {string|string[]} pattern glob pattern as string or an array of + * @param pattern glob pattern as string or an array of * glob patterns for virtual directory structure - * @param {object} options glob options - * @param {@ui5/fs/tracing/Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource[]>} Promise resolving to list of resources + * @param options glob options + * @param options.nodir + * @param trace Trace instance + * @returns Promise resolving to list of resources */ async _byGlob(pattern: string | string[], options: {nodir: boolean}, trace: Trace) { if (!(pattern instanceof Array)) { @@ -104,11 +104,11 @@ class Link extends AbstractReader { /** * Locates resources by path. * - * @private - * @param {string} virPath Virtual path - * @param {object} options Options - * @param {@ui5/fs/tracing/Trace} trace Trace instance - * @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource + * @param virPath Virtual path + * @param options Options + * @param options.nodir + * @param trace Trace instance + * @returns Promise resolving to a single resource */ async _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { if (!virPath.startsWith(this._pathMapping.linkPath)) { diff --git a/src/resourceFactory.ts b/src/resourceFactory.ts index 3c8637eb..7a94094f 100644 --- a/src/resourceFactory.ts +++ b/src/resourceFactory.ts @@ -5,10 +5,10 @@ import FsAdapter from "./adapters/FileSystem.js"; import MemAdapter from "./adapters/Memory.js"; import ReaderCollection from "./ReaderCollection.js"; import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; -import Resource, {Resource_Options} from "./Resource.js"; +import Resource, {Resource_Options, ResourceInterface} from "./Resource.js"; import WriterCollection from "./WriterCollection.js"; import Filter, {Filter_Params} from "./readers/Filter.js"; -import Link from "./readers/Link.js"; +import Link, {Link_Params} from "./readers/Link.js"; import {getLogger} from "@ui5/logger"; import {Project} from "@ui5/project/specifications/Project"; import AbstractReader from "./AbstractReader.js"; @@ -18,7 +18,6 @@ const log = getLogger("resources:resourceFactory"); /** * @module @ui5/fs/resourceFactory * @description A collection of resource related APIs - * @public */ /** @@ -27,22 +26,21 @@ const log = getLogger("resources:resourceFactory"); * If a file system base path is given, file system resource ReaderWriter is returned. * In any other case a virtual one. * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.virBasePath Virtual base path. Must be absolute, POSIX-style, and must end with a slash - * @param {string} [parameters.fsBasePath] + * @param parameters Parameters + * @param parameters.virBasePath Virtual base path. Must be absolute, POSIX-style, and must end with a slash + * @param [parameters.fsBasePath] * File System base path. * If this parameter is supplied, a File System adapter will be created instead of a Memory adapter. * The provided path must be absolute and must use platform-specific path segment separators. - * @param {string[]} [parameters.excludes] List of glob patterns to exclude - * @param {object} [parameters.useGitignore=false] + * @param [parameters.excludes] List of glob patterns to exclude + * @param [parameters.useGitignore] * Whether to apply any excludes defined in an optional .gitignore in the base directory. * This parameter only takes effect in conjunction with the fsBasePath parameter. - * @param {@ui5/project/specifications/Project} [parameters.project] Project this adapter belongs to (if any) - * @returns {@ui5/fs/adapters/FileSystem|@ui5/fs/adapters/Memory} File System- or Virtual Adapter + * @param [parameters.project] Project this adapter belongs to (if any) + * @returns File System- or Virtual Adapter */ export function createAdapter({fsBasePath, virBasePath, project, excludes, useGitignore}: -{fsBasePath: string; virBasePath: string; project: Project; excludes: string[]; useGitignore: boolean} +{fsBasePath?: string; virBasePath: string; project?: Project; excludes?: string[]; useGitignore?: boolean} ) { if (fsBasePath) { return new FsAdapter({fsBasePath, virBasePath, project, excludes, useGitignore}); @@ -54,18 +52,17 @@ export function createAdapter({fsBasePath, virBasePath, project, excludes, useGi /** * Creates a File System adapter and wraps it in a ReaderCollection * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.virBasePath Virtual base path. Must be absolute, POSIX-style, and must end with a slash - * @param {string} parameters.fsBasePath + * @param parameters Parameters + * @param parameters.virBasePath Virtual base path. Must be absolute, POSIX-style, and must end with a slash + * @param parameters.fsBasePath * File System base path. Must be absolute and must use platform-specific path segment separators - * @param {object} [parameters.project] Experimental, internal parameter. Do not use - * @param {string[]} [parameters.excludes] List of glob patterns to exclude - * @param {string} [parameters.name] Name for the reader collection - * @returns {@ui5/fs/ReaderCollection} Reader collection wrapping an adapter + * @param [parameters.project] Experimental, internal parameter. Do not use + * @param [parameters.excludes] List of glob patterns to exclude + * @param [parameters.name] Name for the reader collection + * @returns Reader collection wrapping an adapter */ export function createReader({fsBasePath, virBasePath, project, excludes = [], name}: -{fsBasePath: string; virBasePath: string; project: Project; excludes: string[]; name: string} +{fsBasePath: string; virBasePath: string; project?: Project; excludes?: string[]; name?: string} ) { if (!fsBasePath) { // Creating a reader with a memory adapter seems pointless right now @@ -107,11 +104,10 @@ export function createReader({fsBasePath, virBasePath, project, excludes = [], n /** * Creates a ReaderCollection * - * @public - * @param {object} parameters Parameters - * @param {string} parameters.name The collection name - * @param {@ui5/fs/AbstractReader[]} parameters.readers List of resource readers (all tried in parallel) - * @returns {@ui5/fs/ReaderCollection} Reader collection wrapping provided readers + * @param parameters Parameters + * @param parameters.name The collection name + * @param parameters.readers List of resource readers (all tried in parallel) + * @returns Reader collection wrapping provided readers */ export function createReaderCollection({name, readers}: {name: string; readers: AbstractReader[]}) { return new ReaderCollection({ @@ -123,12 +119,11 @@ export function createReaderCollection({name, readers}: {name: string; readers: /** * Creates a ReaderCollectionPrioritized * - * @public - * @param {object} parameters - * @param {string} parameters.name The collection name - * @param {@ui5/fs/AbstractReader[]} parameters.readers Prioritized list of resource readers + * @param parameters + * @param parameters.name The collection name + * @param parameters.readers Prioritized list of resource readers * (first is tried first) - * @returns {@ui5/fs/ReaderCollectionPrioritized} Reader collection wrapping provided readers + * @returns Reader collection wrapping provided readers */ export function createReaderCollectionPrioritized({name, readers}: {name: string; readers: AbstractReader[]}) { return new ReaderCollectionPrioritized({ @@ -140,12 +135,11 @@ export function createReaderCollectionPrioritized({name, readers}: {name: string /** * Creates a WriterCollection * - * @public - * @param {object} parameters - * @param {string} parameters.name The collection name - * @param {object.} parameters.writerMapping Mapping of virtual base + * @param parameters + * @param parameters.name The collection name + * @param parameters.writerMapping Mapping of virtual base * paths to writers. Path are matched greedy - * @returns {@ui5/fs/WriterCollection} Writer collection wrapping provided writers + * @returns Writer collection wrapping provided writers */ export function createWriterCollection({name, writerMapping}: {name: string; writerMapping: AbstractReaderWriter[]}) { return new WriterCollection({ @@ -158,11 +152,10 @@ export function createWriterCollection({name, writerMapping}: {name: string; wri * Creates a [Resource]{@link @ui5/fs/Resource}. * Accepts the same parameters as the [Resource]{@link @ui5/fs/Resource} constructor. * - * @public - * @param {object} parameters Parameters to be passed to the resource constructor - * @returns {@ui5/fs/Resource} Resource + * @param parameters Parameters to be passed to the resource constructor + * @returns Resource */ -export function createResource(parameters: Resource_Options) { +export function createResource(parameters: Resource_Options): ResourceInterface { return new Resource(parameters); } @@ -173,17 +166,16 @@ export function createResource(parameters: Resource_Options) { * to write modified files into a separate writer, this is usually a Memory adapter. If a file already exists it is * fetched from the memory to work on it in further build steps. * - * @public - * @param {object} parameters - * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers - * @param {@ui5/fs/AbstractReaderWriter} [parameters.writer] A ReaderWriter instance which is + * @param parameters + * @param parameters.reader Single reader or collection of readers + * @param [parameters.writer] A ReaderWriter instance which is * only used for writing files. If not supplied, a Memory adapter will be created. - * @param {string} [parameters.name="workspace"] Name of the collection - * @param {string} [parameters.virBasePath="/"] Virtual base path - * @returns {@ui5/fs/DuplexCollection} DuplexCollection which wraps the provided resource locators + * @param [parameters.name] Name of the collection + * @param [parameters.virBasePath] Virtual base path + * @returns DuplexCollection which wraps the provided resource locators */ export function createWorkspace({reader, writer, virBasePath = "/", name = "workspace"}: -{reader: AbstractReader; writer: AbstractReaderWriter; virBasePath: string; name: string} +{reader: AbstractReader; writer?: AbstractReaderWriter; virBasePath?: string; name?: string} ) { if (!writer) { writer = new MemAdapter({ @@ -203,12 +195,11 @@ export function createWorkspace({reader, writer, virBasePath = "/", name = "work * The provided callback is called for every resource that is retrieved through the * reader and decides whether the resource shall be passed on or dropped. * - * @public - * @param {object} parameters - * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers - * @param {@ui5/fs/readers/Filter~callback} parameters.callback + * @param parameters + * @param parameters.reader Single reader or collection of readers + * @param parameters.callback * Filter function. Will be called for every resource passed through this reader. - * @returns {@ui5/fs/readers/Filter} Reader instance + * @returns Reader instance */ export function createFilterReader(parameters: Filter_Params) { return new Filter(parameters); @@ -232,13 +223,12 @@ export function createFilterReader(parameters: Filter_Params) { * // located at "/resources/my-app-name/Component.js" in the sourceReader * const resource = await linkedReader.byPath("/app/Component.js"); * - * @public - * @param {object} parameters - * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers - * @param {@ui5/fs/readers/Link/PathMapping} parameters.pathMapping - * @returns {@ui5/fs/readers/Link} Reader instance + * @param parameters + * @param parameters.reader Single reader or collection of readers + * @param parameters.pathMapping + * @returns Reader instance */ -export function createLinkReader(parameters) { +export function createLinkReader(parameters: Link_Params) { return new Link(parameters); } @@ -249,11 +239,10 @@ export function createLinkReader(parameters) { * This simulates "flat" resource access, which is for example common for projects of type * "application". * - * @public - * @param {object} parameters - * @param {@ui5/fs/AbstractReader} parameters.reader Single reader or collection of readers - * @param {string} parameters.namespace Project namespace - * @returns {@ui5/fs/readers/Link} Reader instance + * @param parameters + * @param parameters.reader Single reader or collection of readers + * @param parameters.namespace Project namespace + * @returns Reader instance */ export function createFlatReader({reader, namespace}: {reader: AbstractReader; namespace: string}) { return new Link({ @@ -269,9 +258,9 @@ export function createFlatReader({reader, namespace}: {reader: AbstractReader; n * Normalizes virtual glob patterns by prefixing them with * a given virtual base directory path * - * @param {string} virPattern glob pattern for virtual directory structure - * @param {string} virBaseDir virtual base directory path to prefix the given patterns with - * @returns {string[]} A list of normalized glob patterns + * @param virPattern glob pattern for virtual directory structure + * @param virBaseDir virtual base directory path to prefix the given patterns with + * @returns A list of normalized glob patterns */ export function prefixGlobPattern(virPattern: string, virBaseDir: string): string[] { const mm = new minimatch.Minimatch(virPattern); diff --git a/src/tracing/Trace.ts b/src/tracing/Trace.ts index a12e5de5..8af3b4a8 100644 --- a/src/tracing/Trace.ts +++ b/src/tracing/Trace.ts @@ -8,8 +8,6 @@ import summaryTrace, {CollectionsType} from "./traceSummary.js"; /** * Trace * - * @private - * @class */ class Trace { _name!: string; diff --git a/src/tracing/traceSummary.ts b/src/tracing/traceSummary.ts index 6ad2efd7..4fd82b19 100644 --- a/src/tracing/traceSummary.ts +++ b/src/tracing/traceSummary.ts @@ -17,6 +17,9 @@ let traceData: null | { timeDiff?: [number, number]; }; +/** + * + */ function init() { traceData = { startTime: process.hrtime(), @@ -28,11 +31,17 @@ function init() { active = true; } +/** + * + */ function reset() { traceData = null; active = false; } +/** + * + */ function report() { let report = ""; @@ -63,6 +72,9 @@ function report() { log.silly(report); } +/** + * + */ function someTraceStarted() { if (!log.isLevelEnabled("silly")) { return; @@ -78,6 +90,9 @@ function someTraceStarted() { } } +/** + * + */ function someTraceEnded(): Promise { return new Promise(function (resolve) { if (!active) { @@ -102,6 +117,9 @@ function someTraceEnded(): Promise { }); } +/** + * + */ function pathCall() { if (!active) { return; @@ -111,6 +129,9 @@ function pathCall() { } } +/** + * + */ function globCall() { if (!active) { return; @@ -121,6 +142,10 @@ function globCall() { } } +/** + * + * @param name + */ function collection(name: string) { if (!active) { return; diff --git a/src/utils/tsUtils.ts b/src/utils/tsUtils.ts index 7dcbd8d0..8c17e537 100644 --- a/src/utils/tsUtils.ts +++ b/src/utils/tsUtils.ts @@ -1,9 +1,17 @@ import Resource from "../Resource.js"; +/** + * + * @param testString + */ export function isString(testString: unknown): testString is string { return testString instanceof String || String(testString) === testString; } +/** + * + * @param resource + */ export function isMigratedResource(resource: unknown): resource is Resource { // Check if its a fs/Resource v3, function 'hasProject' was // introduced with v3 therefore take it as the indicator diff --git a/test/lib/adapters/AbstractAdapter.ts b/test/lib/adapters/AbstractAdapter.ts index 1f13a889..d0842f7f 100644 --- a/test/lib/adapters/AbstractAdapter.ts +++ b/test/lib/adapters/AbstractAdapter.ts @@ -1,7 +1,7 @@ import test from "ava"; import AbstractAdapter from "../../../src/adapters/AbstractAdapter.js"; import {createResource} from "../../../src/resourceFactory.js"; -import { LegacyResource } from "../../../src/Resource.js"; +import {LegacyResource} from "../../../src/Resource.js"; class MyAbstractAdapter extends AbstractAdapter { } From 3b0a90bc26cb33fb360d9bbb9b65dfd0e57fe60e Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 15:29:09 +0300 Subject: [PATCH 44/69] fix: Autofix eslint findings --- src/ReaderCollectionPrioritized.ts | 2 +- src/readers/Filter.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ReaderCollectionPrioritized.ts b/src/ReaderCollectionPrioritized.ts index 49b19bd3..a8801d46 100644 --- a/src/ReaderCollectionPrioritized.ts +++ b/src/ReaderCollectionPrioritized.ts @@ -1,5 +1,5 @@ import AbstractReader from "./AbstractReader.js"; -import Resource, { ResourceInterface } from "./Resource.js"; +import {ResourceInterface} from "./Resource.js"; import Trace from "./tracing/Trace.js"; /** diff --git a/src/readers/Filter.ts b/src/readers/Filter.ts index cb3db87c..7208e611 100644 --- a/src/readers/Filter.ts +++ b/src/readers/Filter.ts @@ -24,7 +24,6 @@ class Filter extends AbstractReader { _reader: AbstractReader; _callback: (resource: ResourceInterface) => boolean; - /** * Constructor * From 7b0f96e53cb8f98bff7e1a3e344128a2c39ab717 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 15:30:43 +0300 Subject: [PATCH 45/69] fix: Broken interface --- src/readers/Link.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/readers/Link.ts b/src/readers/Link.ts index 69011b96..5f9b502a 100644 --- a/src/readers/Link.ts +++ b/src/readers/Link.ts @@ -5,7 +5,7 @@ import {getLogger} from "@ui5/logger"; const log = getLogger("resources:readers:Link"); import Trace from "../tracing/Trace.js"; -export interface Link_Params {reader: AbstractReader; pathMapping: {linkPath: string; targetPath: string}; +export interface Link_Params {reader: AbstractReader; pathMapping: {linkPath: string; targetPath: string}}; /** * A reader that allows for rewriting paths segments of all resources passed through it. From 55f21c9932508eef2d897ab15059e8880730e96b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 15:45:01 +0300 Subject: [PATCH 46/69] fix: Add JSDoc descriptions --- src/AbstractReader.ts | 15 ++++++--------- src/DuplexCollection.ts | 4 ++-- src/ReaderCollection.ts | 4 ++-- src/ReaderCollectionPrioritized.ts | 4 ++-- src/WriterCollection.ts | 4 ++-- src/adapters/FileSystem.ts | 7 +++---- src/adapters/Memory.ts | 12 +++++------- src/readers/Filter.ts | 4 ++-- src/readers/Link.ts | 10 +++++----- src/tracing/traceSummary.ts | 2 +- 10 files changed, 30 insertions(+), 36 deletions(-) diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index 8c6f2967..714bb6a0 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -81,11 +81,10 @@ class AbstractReader { /** * Locates resources by one or more glob patterns. * - * @param virPattern glob pattern as string or an array of + * @param _virPattern glob pattern as string or an array of * glob patterns for virtual directory structure - * @param _virPattern * @param _options glob options - * @param _options.nodir + * @param _options.nodir Do not match directories * @param _trace Trace instance */ _byGlob(_virPattern: string | string[], @@ -99,10 +98,9 @@ class AbstractReader { /** * Locate resources by matching a single glob pattern. * - * @param pattern glob pattern - * @param _pattern + * @param _pattern glob pattern * @param _options glob options - * @param _options.nodir + * @param _options.nodir Do not match directories * @param _trace Trace instance */ _runGlob(_pattern: string | string[], _options: {nodir: boolean}, _trace: Trace): Promise { @@ -112,10 +110,9 @@ class AbstractReader { /** * Locates resources by path. * - * @param virPath Virtual path - * @param _virPath + * @param _virPath Virtual path * @param _options glob options - * @param _options.nodir + * @param _options.nodir Do not match directories * @param _trace Trace instance */ _byPath(_virPath: string, _options: {nodir: boolean}, _trace: Trace): Promise { diff --git a/src/DuplexCollection.ts b/src/DuplexCollection.ts index 85476184..6baa540f 100644 --- a/src/DuplexCollection.ts +++ b/src/DuplexCollection.ts @@ -51,7 +51,7 @@ class DuplexCollection extends AbstractReaderWriter { * @param virPattern glob pattern as string or an array of * glob patterns for virtual directory structure * @param options glob options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns Promise resolving with a list of resources */ @@ -64,7 +64,7 @@ class DuplexCollection extends AbstractReaderWriter { * * @param virPath Virtual path * @param options Options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns * Promise resolving to a single resource or null if no resource is found diff --git a/src/ReaderCollection.ts b/src/ReaderCollection.ts index 7f3f21a3..61d428a9 100644 --- a/src/ReaderCollection.ts +++ b/src/ReaderCollection.ts @@ -31,7 +31,7 @@ class ReaderCollection extends AbstractReader { * @param pattern glob pattern as string or an array of * glob patterns for virtual directory structure * @param options glob options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns Promise resolving to list of resources */ @@ -49,7 +49,7 @@ class ReaderCollection extends AbstractReader { * * @param virPath Virtual path * @param options Options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns * Promise resolving to a single resource or null if no resource is found diff --git a/src/ReaderCollectionPrioritized.ts b/src/ReaderCollectionPrioritized.ts index a8801d46..fe89dc39 100644 --- a/src/ReaderCollectionPrioritized.ts +++ b/src/ReaderCollectionPrioritized.ts @@ -32,7 +32,7 @@ class ReaderCollectionPrioritized extends AbstractReader { * @param pattern glob pattern as string or an array of * glob patterns for virtual directory structure * @param options glob options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns Promise resolving to list of resources */ @@ -66,7 +66,7 @@ class ReaderCollectionPrioritized extends AbstractReader { * * @param virPath Virtual path * @param options Options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns * Promise resolving to a single resource or null if no resource is found diff --git a/src/WriterCollection.ts b/src/WriterCollection.ts index 81d42372..4f46c76d 100644 --- a/src/WriterCollection.ts +++ b/src/WriterCollection.ts @@ -74,7 +74,7 @@ class WriterCollection extends AbstractReaderWriter { * @param pattern glob pattern as string or an array of * glob patterns for virtual directory structure * @param options glob options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns Promise resolving to list of resources */ @@ -87,7 +87,7 @@ class WriterCollection extends AbstractReaderWriter { * * @param virPath Virtual path * @param options Options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns Promise resolving to a single resource */ diff --git a/src/adapters/FileSystem.ts b/src/adapters/FileSystem.ts index 8155ae7d..f8bd7e8d 100644 --- a/src/adapters/FileSystem.ts +++ b/src/adapters/FileSystem.ts @@ -152,7 +152,7 @@ class FileSystem extends AbstractAdapter { * * @param virPath Absolute virtual path * @param options Options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns Promise resolving to a single resource or null if not found */ @@ -230,8 +230,8 @@ class FileSystem extends AbstractAdapter { /** * Writes the content of a resource to a path. * - * @param resource Resource to write - * @param [options] + * @param anyResource Resource to write + * @param [options] Writer options * @param [options.readOnly] Whether the resource content shall be written read-only * Do not use in conjunction with the drain option. * The written file will be used as the new source of this resources content. @@ -241,7 +241,6 @@ class FileSystem extends AbstractAdapter { * Do not use in conjunction with the readOnly option. * Activating this option might improve overall memory consumption. * This should be used in cases where this is the last access to the resource. - * @param anyResource * E.g. the final write of a resource after all processing is finished. * @returns Promise resolving once data has been written */ diff --git a/src/adapters/Memory.ts b/src/adapters/Memory.ts index 7739b378..8b782b96 100644 --- a/src/adapters/Memory.ts +++ b/src/adapters/Memory.ts @@ -35,8 +35,8 @@ class Memory extends AbstractAdapter { /** * Matches and returns resources from a given map (either _virFiles or _virDirs). * - * @param patterns - * @param resourceMap + * @param patterns glob patterns + * @param resourceMap Resources cache * @returns */ async _matchPatterns(patterns: string[], resourceMap: Record): Promise { @@ -66,8 +66,7 @@ class Memory extends AbstractAdapter { * @param patterns array of glob patterns * @param [options] glob options * @param [options.nodir] Do not match directories - * @param _trace - * @param trace Trace instance + * @param _trace Trace instance * @returns Promise resolving to list of resources */ async _runGlob(patterns: string[], options = {nodir: true}, _trace: Trace) { @@ -103,7 +102,7 @@ class Memory extends AbstractAdapter { * * @param virPath Virtual path * @param options Options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns Promise resolving to a single resource */ @@ -127,8 +126,7 @@ class Memory extends AbstractAdapter { /** * Writes the content of a resource to a path. * - * @param anyResource - * @param resource The Resource to write + * @param anyResource The Resource to write * @returns Promise resolving once data has been written */ async _write(anyResource: Resource | LegacyResource) { diff --git a/src/readers/Filter.ts b/src/readers/Filter.ts index 7208e611..48461b44 100644 --- a/src/readers/Filter.ts +++ b/src/readers/Filter.ts @@ -50,7 +50,7 @@ class Filter extends AbstractReader { * @param pattern glob pattern as string or an array of * glob patterns for virtual directory structure * @param options glob options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns Promise resolving to list of resources */ @@ -64,7 +64,7 @@ class Filter extends AbstractReader { * * @param virPath Virtual path * @param options Options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns Promise resolving to a single resource */ diff --git a/src/readers/Link.ts b/src/readers/Link.ts index 5f9b502a..163c5c73 100644 --- a/src/readers/Link.ts +++ b/src/readers/Link.ts @@ -43,9 +43,9 @@ class Link extends AbstractReader { * * @param parameters Parameters * @param parameters.reader The resource reader or collection to wrap - * @param parameters.pathMapping - * @param parameters.pathMapping.linkPath - * @param parameters.pathMapping.targetPath + * @param parameters.pathMapping Path mapping for a [Link]{@link @ui5/fs/readers/Link} + * @param parameters.pathMapping.linkPath Path to match and replace in the requested path or pattern + * @param parameters.pathMapping.targetPath Path to use as a replacement in the request for the source reader */ constructor({reader, pathMapping}: Link_Params) { super(); @@ -66,7 +66,7 @@ class Link extends AbstractReader { * @param pattern glob pattern as string or an array of * glob patterns for virtual directory structure * @param options glob options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns Promise resolving to list of resources */ @@ -106,7 +106,7 @@ class Link extends AbstractReader { * * @param virPath Virtual path * @param options Options - * @param options.nodir + * @param options.nodir Do not match directories * @param trace Trace instance * @returns Promise resolving to a single resource */ diff --git a/src/tracing/traceSummary.ts b/src/tracing/traceSummary.ts index 4fd82b19..8bf03a32 100644 --- a/src/tracing/traceSummary.ts +++ b/src/tracing/traceSummary.ts @@ -144,7 +144,7 @@ function globCall() { /** * - * @param name + * @param name TraceData collection name */ function collection(name: string) { if (!active) { From d2407c8d9dd4e85ed05286a27a41b55f48578150 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 15:50:20 +0300 Subject: [PATCH 47/69] fix: Add JSDoc descriptions --- src/AbstractReaderWriter.ts | 12 ++++++++++-- src/ResourceFacade.ts | 3 +-- src/ResourceTagCollection.ts | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/AbstractReaderWriter.ts b/src/AbstractReaderWriter.ts index e918a3bc..dc82e1b5 100644 --- a/src/AbstractReaderWriter.ts +++ b/src/AbstractReaderWriter.ts @@ -54,8 +54,16 @@ class AbstractReaderWriter extends AbstractReader { * * @param _resource Resource to write * @param [_options] Write options, see above - * @param [_options.drain] - * @param [_options.readOnly] + * @param [_options.drain] Whether the resource content shall be emptied during the write process. + * Do not use in conjunction with the readOnly option. + * Activating this option might improve overall memory consumption. + * This should be used in cases where this is the last access to the resource. + * E.g. the final write of a resource after all processing is finished. + * @param [_options.readOnly] Whether the resource content shall be written read-only + * Do not use in conjunction with the drain option. + * The written file will be used as the new source of this resources content. + * Therefore the written file should not be altered by any means. + * Activating this option might improve overall memory consumption. */ _write(_resource: Resource, _options?: {drain?: boolean; readOnly?: boolean}): Promise { throw new Error("Not implemented"); diff --git a/src/ResourceFacade.ts b/src/ResourceFacade.ts index ff6bb0f8..23d69de3 100644 --- a/src/ResourceFacade.ts +++ b/src/ResourceFacade.ts @@ -58,8 +58,7 @@ class ResourceFacade implements ResourceInterface { /** * Sets the resources path * - * @param _path - * @param path (Virtual) path of the resource + * @param _path (Virtual) path of the resource */ setPath(_path: string) { throw new Error(`The path of a ResourceFacade can't be changed`); diff --git a/src/ResourceTagCollection.ts b/src/ResourceTagCollection.ts index 3bfce49e..4d2a1032 100644 --- a/src/ResourceTagCollection.ts +++ b/src/ResourceTagCollection.ts @@ -8,7 +8,7 @@ interface PathTagsInterface { }; /** * - * @param elem + * @param elem Variable to test if it's with a PathTagsInterface */ export function isPathTagsInterface(elem: unknown): elem is PathTagsInterface { return typeof elem === "object"; From d1fac86f65164e251974e249ef85d4d6f59bfbb3 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 15:58:45 +0300 Subject: [PATCH 48/69] fix: Add JSDoc descriptions --- src/AbstractReaderWriter.ts | 2 +- src/DuplexCollection.ts | 2 +- src/ReaderCollectionPrioritized.ts | 2 +- src/ResourceTagCollection.ts | 2 +- src/WriterCollection.ts | 12 ++++++++++-- src/readers/Link.ts | 12 ++++++++---- src/resourceFactory.ts | 20 +++++++++++--------- src/utils/tsUtils.ts | 4 ++-- 8 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/AbstractReaderWriter.ts b/src/AbstractReaderWriter.ts index dc82e1b5..ec7e1650 100644 --- a/src/AbstractReaderWriter.ts +++ b/src/AbstractReaderWriter.ts @@ -32,7 +32,7 @@ class AbstractReaderWriter extends AbstractReader { * Writes the content of a resource to a path. * * @param resource Resource to write - * @param [options] + * @param [options] Write options * @param [options.readOnly] Whether the resource content shall be written read-only * Do not use in conjunction with the drain option. * The written file will be used as the new source of this resources content. diff --git a/src/DuplexCollection.ts b/src/DuplexCollection.ts index 6baa540f..a552ece9 100644 --- a/src/DuplexCollection.ts +++ b/src/DuplexCollection.ts @@ -17,7 +17,7 @@ class DuplexCollection extends AbstractReaderWriter { /** * The Constructor. * - * @param parameters + * @param parameters Parameters * @param parameters.reader Single reader or collection of readers * @param parameters.writer * A ReaderWriter instance which is only used for writing files diff --git a/src/ReaderCollectionPrioritized.ts b/src/ReaderCollectionPrioritized.ts index fe89dc39..ae136955 100644 --- a/src/ReaderCollectionPrioritized.ts +++ b/src/ReaderCollectionPrioritized.ts @@ -13,7 +13,7 @@ class ReaderCollectionPrioritized extends AbstractReader { /** * The constructor. * - * @param parameters + * @param parameters Parameters * @param parameters.name The collection name * @param [parameters.readers] * Prioritized list of resource readers (tried in the order provided). diff --git a/src/ResourceTagCollection.ts b/src/ResourceTagCollection.ts index 4d2a1032..14302b38 100644 --- a/src/ResourceTagCollection.ts +++ b/src/ResourceTagCollection.ts @@ -8,7 +8,7 @@ interface PathTagsInterface { }; /** * - * @param elem Variable to test if it's with a PathTagsInterface + * @param elem Variable to test if it's with a PathTagsInterface type */ export function isPathTagsInterface(elem: unknown): elem is PathTagsInterface { return typeof elem === "object"; diff --git a/src/WriterCollection.ts b/src/WriterCollection.ts index 4f46c76d..2e12de3e 100644 --- a/src/WriterCollection.ts +++ b/src/WriterCollection.ts @@ -100,8 +100,16 @@ class WriterCollection extends AbstractReaderWriter { * * @param resource The Resource to write * @param [options] Write options, see above - * @param [options.drain] - * @param [options.readOnly] + * @param [options.drain] Whether the resource content shall be emptied during the write process. + * Do not use in conjunction with the readOnly option. + * Activating this option might improve overall memory consumption. + * This should be used in cases where this is the last access to the resource. + * E.g. the final write of a resource after all processing is finished. + * @param [options.readOnly] Whether the resource content shall be written read-only + * Do not use in conjunction with the drain option. + * The written file will be used as the new source of this resources content. + * Therefore the written file should not be altered by any means. + * Activating this option might improve overall memory consumption. * @returns Promise resolving once data has been written */ _write(resource: Resource, options?: {drain?: boolean; readOnly?: boolean}) { diff --git a/src/readers/Link.ts b/src/readers/Link.ts index 163c5c73..99d4e5f4 100644 --- a/src/readers/Link.ts +++ b/src/readers/Link.ts @@ -5,7 +5,13 @@ import {getLogger} from "@ui5/logger"; const log = getLogger("resources:readers:Link"); import Trace from "../tracing/Trace.js"; -export interface Link_Params {reader: AbstractReader; pathMapping: {linkPath: string; targetPath: string}}; +export interface Link_Args { + reader: AbstractReader; + pathMapping: { + linkPath: string; + targetPath: string; + }; +}; /** * A reader that allows for rewriting paths segments of all resources passed through it. @@ -44,10 +50,8 @@ class Link extends AbstractReader { * @param parameters Parameters * @param parameters.reader The resource reader or collection to wrap * @param parameters.pathMapping Path mapping for a [Link]{@link @ui5/fs/readers/Link} - * @param parameters.pathMapping.linkPath Path to match and replace in the requested path or pattern - * @param parameters.pathMapping.targetPath Path to use as a replacement in the request for the source reader */ - constructor({reader, pathMapping}: Link_Params) { + constructor({reader, pathMapping}: Link_Args) { super(); if (!reader) { throw new Error(`Missing parameter "reader"`); diff --git a/src/resourceFactory.ts b/src/resourceFactory.ts index 7a94094f..aa88891c 100644 --- a/src/resourceFactory.ts +++ b/src/resourceFactory.ts @@ -8,7 +8,7 @@ import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; import Resource, {Resource_Options, ResourceInterface} from "./Resource.js"; import WriterCollection from "./WriterCollection.js"; import Filter, {Filter_Params} from "./readers/Filter.js"; -import Link, {Link_Params} from "./readers/Link.js"; +import Link, {Link_Args} from "./readers/Link.js"; import {getLogger} from "@ui5/logger"; import {Project} from "@ui5/project/specifications/Project"; import AbstractReader from "./AbstractReader.js"; @@ -119,7 +119,7 @@ export function createReaderCollection({name, readers}: {name: string; readers: /** * Creates a ReaderCollectionPrioritized * - * @param parameters + * @param parameters Parameters * @param parameters.name The collection name * @param parameters.readers Prioritized list of resource readers * (first is tried first) @@ -135,7 +135,7 @@ export function createReaderCollectionPrioritized({name, readers}: {name: string /** * Creates a WriterCollection * - * @param parameters + * @param parameters Parameters * @param parameters.name The collection name * @param parameters.writerMapping Mapping of virtual base * paths to writers. Path are matched greedy @@ -166,7 +166,7 @@ export function createResource(parameters: Resource_Options): ResourceInterface * to write modified files into a separate writer, this is usually a Memory adapter. If a file already exists it is * fetched from the memory to work on it in further build steps. * - * @param parameters + * @param parameters Parameters * @param parameters.reader Single reader or collection of readers * @param [parameters.writer] A ReaderWriter instance which is * only used for writing files. If not supplied, a Memory adapter will be created. @@ -195,7 +195,7 @@ export function createWorkspace({reader, writer, virBasePath = "/", name = "work * The provided callback is called for every resource that is retrieved through the * reader and decides whether the resource shall be passed on or dropped. * - * @param parameters + * @param parameters Parameters * @param parameters.reader Single reader or collection of readers * @param parameters.callback * Filter function. Will be called for every resource passed through this reader. @@ -223,12 +223,14 @@ export function createFilterReader(parameters: Filter_Params) { * // located at "/resources/my-app-name/Component.js" in the sourceReader * const resource = await linkedReader.byPath("/app/Component.js"); * - * @param parameters + * @param parameters Parameters * @param parameters.reader Single reader or collection of readers - * @param parameters.pathMapping + * @param parameters.pathMapping Path mapping for a [Link]{@link @ui5/fs/readers/Link} + * @param parameters.pathMapping.linkPath Path to match and replace in the requested path or pattern + * @param parameters.pathMapping.targetPath Path to use as a replacement in the request for the source reader * @returns Reader instance */ -export function createLinkReader(parameters: Link_Params) { +export function createLinkReader(parameters: Link_Args) { return new Link(parameters); } @@ -239,7 +241,7 @@ export function createLinkReader(parameters: Link_Params) { * This simulates "flat" resource access, which is for example common for projects of type * "application". * - * @param parameters + * @param parameters Parameters * @param parameters.reader Single reader or collection of readers * @param parameters.namespace Project namespace * @returns Reader instance diff --git a/src/utils/tsUtils.ts b/src/utils/tsUtils.ts index 8c17e537..de18ccb4 100644 --- a/src/utils/tsUtils.ts +++ b/src/utils/tsUtils.ts @@ -2,7 +2,7 @@ import Resource from "../Resource.js"; /** * - * @param testString + * @param testString Variable to test if it's a string type */ export function isString(testString: unknown): testString is string { return testString instanceof String || String(testString) === testString; @@ -10,7 +10,7 @@ export function isString(testString: unknown): testString is string { /** * - * @param resource + * @param resource Variable to test if it's with a Resource type */ export function isMigratedResource(resource: unknown): resource is Resource { // Check if its a fs/Resource v3, function 'hasProject' was From 49fd1d1e79cffba18c946b5ac36c2eaa4e28d914 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 16:55:20 +0300 Subject: [PATCH 49/69] refactor: Migrate Resource to ResourceInterface --- src/AbstractReaderWriter.ts | 6 +-- src/DuplexCollection.ts | 4 +- src/ReaderCollection.ts | 8 ++-- src/ResourceFacade.ts | 3 +- src/ResourceTagCollection.ts | 4 +- src/WriterCollection.ts | 4 +- src/adapters/AbstractAdapter.ts | 12 ++--- src/adapters/FileSystem.ts | 11 +++-- src/adapters/Memory.ts | 22 ++++----- src/resourceFactory.ts | 3 +- src/utils/tsUtils.ts | 4 +- test/lib/resources.ts | 82 ++++++++++++++++++--------------- 12 files changed, 87 insertions(+), 76 deletions(-) diff --git a/src/AbstractReaderWriter.ts b/src/AbstractReaderWriter.ts index ec7e1650..de30031d 100644 --- a/src/AbstractReaderWriter.ts +++ b/src/AbstractReaderWriter.ts @@ -1,5 +1,5 @@ import AbstractReader from "./AbstractReader.js"; -import Resource from "./Resource.js"; +import {ResourceInterface} from "./Resource.js"; /** * Abstract resource locator implementing the general API for reading and writing resources @@ -45,7 +45,7 @@ class AbstractReaderWriter extends AbstractReader { * E.g. the final write of a resource after all processing is finished. * @returns Promise resolving once data has been written */ - write(resource: Resource, options = {drain: false, readOnly: false}): Promise { + write(resource: ResourceInterface, options = {drain: false, readOnly: false}): Promise { return this._write(resource, options); } @@ -65,7 +65,7 @@ class AbstractReaderWriter extends AbstractReader { * Therefore the written file should not be altered by any means. * Activating this option might improve overall memory consumption. */ - _write(_resource: Resource, _options?: {drain?: boolean; readOnly?: boolean}): Promise { + _write(_resource: ResourceInterface, _options?: {drain?: boolean; readOnly?: boolean}): Promise { throw new Error("Not implemented"); } } diff --git a/src/DuplexCollection.ts b/src/DuplexCollection.ts index a552ece9..6ab2215a 100644 --- a/src/DuplexCollection.ts +++ b/src/DuplexCollection.ts @@ -1,7 +1,7 @@ import AbstractReader from "./AbstractReader.js"; import AbstractReaderWriter from "./AbstractReaderWriter.js"; import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; -import Resource from "./Resource.js"; +import {ResourceInterface} from "./Resource.js"; import Trace from "./tracing/Trace.js"; /** @@ -79,7 +79,7 @@ class DuplexCollection extends AbstractReaderWriter { * @param resource The Resource to write * @returns Promise resolving once data has been written */ - _write(resource: Resource) { + _write(resource: ResourceInterface) { return this._writer.write(resource); } } diff --git a/src/ReaderCollection.ts b/src/ReaderCollection.ts index 61d428a9..53a5f5fd 100644 --- a/src/ReaderCollection.ts +++ b/src/ReaderCollection.ts @@ -1,5 +1,5 @@ import AbstractReader from "./AbstractReader.js"; -import Resource from "./Resource.js"; +import {ResourceInterface} from "./Resource.js"; import Trace from "./tracing/Trace.js"; /** @@ -13,12 +13,12 @@ class ReaderCollection extends AbstractReader { * The constructor. * * @param parameters Parameters - * @param parameters.name The collection name + * @param [parameters.name] The collection name * @param [parameters.readers] * List of resource readers (all tried in parallel). * If none are provided, the collection will never return any results. */ - constructor({name, readers}: {name: string; readers?: AbstractReader[]}) { + constructor({name, readers}: {name?: string; readers?: AbstractReader[]}) { super(name); // Remove any undefined (empty) readers from array @@ -40,7 +40,7 @@ class ReaderCollection extends AbstractReader { return resourceLocator._byGlob(pattern, options, trace); })).then((result) => { trace.collection(this._name!); - return Array.prototype.concat.apply([], result) as Resource[]; // Flatten array + return Array.prototype.concat.apply([], result) as ResourceInterface[]; // Flatten array }); } diff --git a/src/ResourceFacade.ts b/src/ResourceFacade.ts index 23d69de3..7adbe111 100644 --- a/src/ResourceFacade.ts +++ b/src/ResourceFacade.ts @@ -1,8 +1,7 @@ import posixPath from "node:path/posix"; -import {ResourceInterface} from "./Resource.js"; import {Buffer} from "node:buffer"; import stream from "node:stream"; -import {Resource_CreateReadableStream} from "./Resource.js"; +import {Resource_CreateReadableStream, ResourceInterface} from "./Resource.js"; import {Project} from "@ui5/project/specifications/Project"; /** diff --git a/src/ResourceTagCollection.ts b/src/ResourceTagCollection.ts index 14302b38..dde4dc66 100644 --- a/src/ResourceTagCollection.ts +++ b/src/ResourceTagCollection.ts @@ -1,6 +1,6 @@ const tagNamespaceRegExp = /^[a-z][a-z0-9]+$/; // part before the colon const tagNameRegExp = /^[A-Z][A-Za-z0-9]+$/; // part after the colon -import Resource from "./Resource.js"; +import {ResourceInterface} from "./Resource.js"; import ResourceFacade from "./ResourceFacade.js"; interface PathTagsInterface { @@ -94,7 +94,7 @@ class ResourceTagCollection { return false; } - _getPath(resourcePath: ResourceFacade | Resource | string): string { + _getPath(resourcePath: ResourceInterface | string): string { if (typeof resourcePath !== "string") { if (resourcePath instanceof ResourceFacade) { resourcePath = resourcePath.getConcealedResource().getPath(); diff --git a/src/WriterCollection.ts b/src/WriterCollection.ts index 2e12de3e..cced9e7b 100644 --- a/src/WriterCollection.ts +++ b/src/WriterCollection.ts @@ -2,7 +2,7 @@ import AbstractReaderWriter from "./AbstractReaderWriter.js"; import ReaderCollection from "./ReaderCollection.js"; import escapeStringRegExp from "escape-string-regexp"; import Trace from "./tracing/Trace.js"; -import Resource from "./Resource.js"; +import {ResourceInterface} from "./Resource.js"; /** * Resource Locator WriterCollection @@ -112,7 +112,7 @@ class WriterCollection extends AbstractReaderWriter { * Activating this option might improve overall memory consumption. * @returns Promise resolving once data has been written */ - _write(resource: Resource, options?: {drain?: boolean; readOnly?: boolean}) { + _write(resource: ResourceInterface, options?: {drain?: boolean; readOnly?: boolean}) { const resourcePath = resource.getPath(); const basePathMatch = resourcePath.match(this._basePathRegex); diff --git a/src/adapters/AbstractAdapter.ts b/src/adapters/AbstractAdapter.ts index b0d726a4..26afc3e2 100644 --- a/src/adapters/AbstractAdapter.ts +++ b/src/adapters/AbstractAdapter.ts @@ -4,7 +4,7 @@ const log = getLogger("resources:adapters:AbstractAdapter"); import {minimatch} from "minimatch"; import micromatch from "micromatch"; import AbstractReaderWriter from "../AbstractReaderWriter.js"; -import Resource, {Resource_Options, LegacyResource} from "../Resource.js"; +import Resource, {Resource_Options, LegacyResource, ResourceInterface} from "../Resource.js"; import type {Project} from "@ui5/project/specifications/Project"; import Trace from "../tracing/Trace.js"; import {isMigratedResource} from "../utils/tsUtils.js"; @@ -64,7 +64,7 @@ class AbstractAdapter extends AbstractReaderWriter { * @param trace Trace instance * @returns Promise resolving to list of resources */ - async _byGlob(virPattern: string | string[], options = {nodir: true}, trace: Trace): Promise { + async _byGlob(virPattern: string | string[], options = {nodir: true}, trace: Trace): Promise { const excludes = this._excludesNegated; if (!(virPattern instanceof Array)) { @@ -199,14 +199,14 @@ class AbstractAdapter extends AbstractReaderWriter { return resultGlobs; } - _createResource(parameters: Resource_Options) { + _createResource(parameters: Resource_Options): ResourceInterface { if (this._project) { parameters.project = this._project; } return new Resource(parameters); } - _migrateResource(resource: LegacyResource | Resource) { + _migrateResource(resource: LegacyResource | ResourceInterface): Promise | ResourceInterface { // This function only returns a promise if a migration is necessary. // Since this is rarely the case, we therefore reduce the amount of // created Promises by making this differentiation @@ -219,7 +219,7 @@ class AbstractAdapter extends AbstractReaderWriter { return this._createFromLegacyResource(resource); } - async _createFromLegacyResource(resource: LegacyResource) { + async _createFromLegacyResource(resource: LegacyResource): Promise { const options = { path: resource._path, statInfo: resource._statInfo, @@ -236,7 +236,7 @@ class AbstractAdapter extends AbstractReaderWriter { return new Resource(options); } - _assignProjectToResource(resource: Resource) { + _assignProjectToResource(resource: ResourceInterface) { if (this._project) { // Assign project to resource if necessary if (resource.hasProject()) { diff --git a/src/adapters/FileSystem.ts b/src/adapters/FileSystem.ts index f8bd7e8d..c78d9f12 100644 --- a/src/adapters/FileSystem.ts +++ b/src/adapters/FileSystem.ts @@ -12,7 +12,7 @@ import {PassThrough} from "node:stream"; import AbstractAdapter from "./AbstractAdapter.js"; import type {Project} from "@ui5/project/specifications/Project"; import Trace from "../tracing/Trace.js"; -import Resource, {LegacyResource, Resource_Options} from "../Resource.js"; +import {LegacyResource, Resource_Options, ResourceInterface} from "../Resource.js"; const READ_ONLY_MODE = 0o444; const ADAPTER_NAME = "FileSystem"; @@ -73,7 +73,7 @@ class FileSystem extends AbstractAdapter { }; trace.globCall(); - const promises: Promise[] = []; + const promises: Promise[] = []; if (!opt.onlyFiles && patterns.includes("")) { // Match physical root directory promises.push(new Promise((resolve, reject) => { fs.stat(this._fsBasePath, (err, stat) => { @@ -144,7 +144,7 @@ class FileSystem extends AbstractAdapter { const results = await Promise.all(promises); // Flatten results - return Array.prototype.concat.apply([], results).filter(($) => $) as Resource[]; + return Array.prototype.concat.apply([], results).filter(($) => $) as ResourceInterface[]; } /** @@ -244,9 +244,10 @@ class FileSystem extends AbstractAdapter { * E.g. the final write of a resource after all processing is finished. * @returns Promise resolving once data has been written */ - async _write(anyResource: LegacyResource | Resource, {drain, readOnly}: {drain?: boolean; readOnly?: boolean}) { + async _write(anyResource: LegacyResource | ResourceInterface, + {drain, readOnly}: {drain?: boolean; readOnly?: boolean}) { const potentialResourceP = this._migrateResource(anyResource); - let resource: Resource; + let resource: ResourceInterface; if (potentialResourceP instanceof Promise) { // Only await if the migrate function returned a promise // Otherwise await would automatically create a Promise, causing unwanted overhead diff --git a/src/adapters/Memory.ts b/src/adapters/Memory.ts index 8b782b96..a636bc3e 100644 --- a/src/adapters/Memory.ts +++ b/src/adapters/Memory.ts @@ -3,7 +3,7 @@ const log = getLogger("resources:adapters:Memory"); import micromatch from "micromatch"; import AbstractAdapter from "./AbstractAdapter.js"; import {Project} from "@ui5/project/specifications/Project"; -import Resource, {LegacyResource, ResourceInterface} from "../Resource.js"; +import {LegacyResource, ResourceInterface} from "../Resource.js"; import Trace from "../tracing/Trace.js"; const ADAPTER_NAME = "Memory"; @@ -14,8 +14,8 @@ const ADAPTER_NAME = "Memory"; * @alias @ui5/fs/adapters/Memory */ class Memory extends AbstractAdapter { - _virFiles: Record; - _virDirs: Record; + _virFiles: Record; + _virDirs: Record; /** * The constructor. @@ -28,8 +28,8 @@ class Memory extends AbstractAdapter { */ constructor({virBasePath, project, excludes}: {virBasePath: string; project?: Project; excludes?: string[]}) { super({virBasePath, project, excludes}); - this._virFiles = Object.create(null) as Record; // map full of files - this._virDirs = Object.create(null) as Record; // map full of directories + this._virFiles = Object.create(null) as Record; // map full of files + this._virDirs = Object.create(null) as Record; // map full of directories } /** @@ -39,20 +39,20 @@ class Memory extends AbstractAdapter { * @param resourceMap Resources cache * @returns */ - async _matchPatterns(patterns: string[], resourceMap: Record): Promise { + async _matchPatterns(patterns: string[], resourceMap: Record): Promise { const resourcePaths = Object.keys(resourceMap); const matchedPaths = micromatch(resourcePaths, patterns, { dot: true, }); return await Promise.all(matchedPaths.map((virPath) => { - const resource: Resource = resourceMap[virPath]; + const resource: ResourceInterface = resourceMap[virPath]; if (resource) { return this._cloneResource(resource); } }).filter(($) => !!$)); } - async _cloneResource(resource: Resource): Promise { + async _cloneResource(resource: ResourceInterface): Promise { const clonedResource = await resource.clone(); if (this._project) { clonedResource.setProject(this._project); @@ -114,7 +114,7 @@ class Memory extends AbstractAdapter { trace.pathCall(); - const resource: Resource = this._virFiles[relPath]; + const resource: ResourceInterface = this._virFiles[relPath]; if (!resource || (options.nodir && resource.getStatInfo().isDirectory?.())) { return null; @@ -129,9 +129,9 @@ class Memory extends AbstractAdapter { * @param anyResource The Resource to write * @returns Promise resolving once data has been written */ - async _write(anyResource: Resource | LegacyResource) { + async _write(anyResource: ResourceInterface | LegacyResource) { const migratedResource = this._migrateResource(anyResource); - let resource: Resource; + let resource: ResourceInterface; if (migratedResource instanceof Promise) { // Only await if the migrate function returned a promise // Otherwise await would automatically create a Promise, causing unwanted overhead diff --git a/src/resourceFactory.ts b/src/resourceFactory.ts index aa88891c..ddd69d23 100644 --- a/src/resourceFactory.ts +++ b/src/resourceFactory.ts @@ -141,7 +141,8 @@ export function createReaderCollectionPrioritized({name, readers}: {name: string * paths to writers. Path are matched greedy * @returns Writer collection wrapping provided writers */ -export function createWriterCollection({name, writerMapping}: {name: string; writerMapping: AbstractReaderWriter[]}) { +export function createWriterCollection({name, writerMapping}: +{name: string; writerMapping: Record}) { return new WriterCollection({ name, writerMapping, diff --git a/src/utils/tsUtils.ts b/src/utils/tsUtils.ts index de18ccb4..ba49eef5 100644 --- a/src/utils/tsUtils.ts +++ b/src/utils/tsUtils.ts @@ -1,4 +1,4 @@ -import Resource from "../Resource.js"; +import Resource, {ResourceInterface} from "../Resource.js"; /** * @@ -12,7 +12,7 @@ export function isString(testString: unknown): testString is string { * * @param resource Variable to test if it's with a Resource type */ -export function isMigratedResource(resource: unknown): resource is Resource { +export function isMigratedResource(resource: unknown): resource is Resource | ResourceInterface { // Check if its a fs/Resource v3, function 'hasProject' was // introduced with v3 therefore take it as the indicator return !!resource && typeof resource === "object" && ("hasProject" in resource); diff --git a/test/lib/resources.ts b/test/lib/resources.ts index 415e2500..2a76e96c 100644 --- a/test/lib/resources.ts +++ b/test/lib/resources.ts @@ -2,25 +2,35 @@ import test from "ava"; import sinon from "sinon"; import {readFile} from "node:fs/promises"; +// const test = anyTest as TestFn<{ +// // buildLogger: BuildLogger; +// // logStub: sinon.SinonStub; +// // logHandler: sinon.SinonStub; +// // metadataHandler: sinon.SinonStub; +// // statusHandler: sinon.SinonStub; +// }>; + import {createAdapter, createFilterReader, createFlatReader, createLinkReader, createResource} from "../../src/resourceFactory.js"; +import {Project} from "@ui5/project/specifications/Project"; -test.afterEach.always((_t) => { +test.afterEach.always(() => { sinon.restore(); }); -function getFileContent(path) { +function getFileContent(path: string) { return readFile(path, "utf8"); } -async function fileEqual(t, actual, expected) { +async function fileEqual(t, actual: string, expected: string) { const actualContent = await getFileContent(actual); const expectedContent = await getFileContent(expected); t.is(actualContent, expectedContent); } ["FileSystem", "Memory"].forEach((adapter) => { - async function getAdapter(config) { + async function getAdapter(config: + {fsBasePath?: string; virBasePath: string; project?: Project; excludes?: string[]; useGitignore?: boolean}) { if (adapter === "Memory") { const fsAdapter = createAdapter(config); const fsResources = await fsAdapter.byGlob("**/*"); @@ -51,11 +61,11 @@ async function fileEqual(t, actual, expected) { }); // Get resource from one readerWriter - const resource = await source.byPath("/app/index.html"); + const resource = await source!.byPath("/app/index.html"); // Write resource content to another readerWriter - resource.setPath("/dest/index_readableStreamTest.html"); - await dest.write(resource); + resource!.setPath("/dest/index_readableStreamTest.html"); + await dest!.write(resource); t.notThrows(async () => { if (adapter === "FileSystem") { @@ -64,8 +74,8 @@ async function fileEqual(t, actual, expected) { "./test/tmp/readerWriters/application.a/simple-read-write/index_readableStreamTest.html", "./test/fixtures/application.a/webapp/index.html"); } else { - const destResource = await dest.byPath("/dest/index_readableStreamTest.html"); - t.deepEqual(await destResource.getString(), await resource.getString()); + const destResource = await dest!.byPath("/dest/index_readableStreamTest.html"); + t.deepEqual(await destResource!.getString(), await resource!.getString()); } }); }); @@ -81,23 +91,23 @@ async function fileEqual(t, actual, expected) { string: "MyInitialContent", }); - await dest.write(resource); + await dest!.write(resource); resource.setString("MyNewContent"); - const resource1 = await dest.byPath("/dest/writer/content/test.js"); + const resource1 = await dest!.byPath("/dest/writer/content/test.js"); t.is(await resource.getString(), "MyNewContent"); - t.is(await resource1.getString(), "MyInitialContent"); + t.is(await resource1!.getString(), "MyInitialContent"); t.is(await resource.getString(), "MyNewContent"); - t.is(await resource1.getString(), "MyInitialContent"); + t.is(await resource1!.getString(), "MyInitialContent"); - await dest.write(resource); + await dest!.write(resource); - const resource2 = await dest.byPath("/dest/writer/content/test.js"); + const resource2 = await dest!.byPath("/dest/writer/content/test.js"); t.is(await resource.getString(), "MyNewContent"); - t.is(await resource2.getString(), "MyNewContent"); + t.is(await resource2!.getString(), "MyNewContent"); }); test(adapter + ": Create resource, write and change path", async (t) => { @@ -111,34 +121,34 @@ async function fileEqual(t, actual, expected) { string: "MyInitialContent", }); - await dest.write(resource); + await dest!.write(resource); resource.setPath("/dest/writer/path/test2.js"); - const resourceOldPath = await dest.byPath("/dest/writer/path/test.js"); - const resourceNewPath = await dest.byPath("/dest/writer/path/test2.js"); + const resourceOldPath = await dest!.byPath("/dest/writer/path/test.js"); + const resourceNewPath = await dest!.byPath("/dest/writer/path/test2.js"); - t.is(await resource.getPath(), "/dest/writer/path/test2.js"); + t.is(resource.getPath(), "/dest/writer/path/test2.js"); t.truthy(resourceOldPath); - t.is(await resourceOldPath.getString(), await resource.getString()); - t.is(await resourceOldPath.getPath(), "/dest/writer/path/test.js"); - t.not(resourceNewPath); + t.is(await resourceOldPath!.getString(), await resource.getString()); + t.is(resourceOldPath!.getPath(), "/dest/writer/path/test.js"); + t.not(resourceNewPath, undefined); - await dest.write(resource); + await dest!.write(resource); - const resourceOldPath1 = await dest.byPath("/dest/writer/path/test.js"); - const resourceNewPath1 = await dest.byPath("/dest/writer/path/test2.js"); + const resourceOldPath1 = await dest!.byPath("/dest/writer/path/test.js"); + const resourceNewPath1 = await dest!.byPath("/dest/writer/path/test2.js"); - t.is(await resource.getPath(), "/dest/writer/path/test2.js"); + t.is(resource.getPath(), "/dest/writer/path/test2.js"); t.truthy(resourceNewPath1); - t.is(await resourceNewPath1.getString(), await resource.getString()); - t.is(await resourceNewPath1.getPath(), "/dest/writer/path/test2.js"); - t.not(resourceOldPath1); + t.is(await resourceNewPath1!.getString(), await resource.getString()); + t.is(resourceNewPath1!.getPath(), "/dest/writer/path/test2.js"); + t.not(resourceOldPath1, undefined); }); test(adapter + ": Create a resource with a path different from the path configured in the adapter", async (t) => { - t.pass(2); + t.pass("2"); const dest = await getAdapter({ fsBasePath: "./test/tmp/writer/", virBasePath: "/dest2/writer/", @@ -149,7 +159,7 @@ async function fileEqual(t, actual, expected) { string: "MyContent", }); - const error = await t.throwsAsync(dest.write(resource)); + const error = await t.throwsAsync(dest!.write(resource)); t.is(error.message, "Failed to write resource with virtual path '/dest2/tmp/test.js': Path must start with the " + "configured virtual base path of the adapter. Base path: '/dest2/writer/'", @@ -158,7 +168,7 @@ async function fileEqual(t, actual, expected) { test(adapter + ": Create a resource with a path above the path configured in the adapter", async (t) => { - t.pass(2); + t.pass("2"); const dest = await getAdapter({ fsBasePath: "./test/tmp/writer/", virBasePath: "/dest2/writer/", @@ -178,7 +188,7 @@ async function fileEqual(t, actual, expected) { test(adapter + ": Create a resource with a path resolving outside the path configured in the adapter", async (t) => { - t.pass(2); + t.pass("2"); const dest = await getAdapter({ fsBasePath: "./test/tmp/writer/", virBasePath: "/dest/writer/", @@ -228,7 +238,7 @@ async function fileEqual(t, actual, expected) { virBasePath: "/resources/app/", }); const transformedSource = createFlatReader({ - reader: source, + reader: source!, namespace: "app", }); @@ -243,7 +253,7 @@ async function fileEqual(t, actual, expected) { virBasePath: "/resources/app/", }); const transformedSource = createLinkReader({ - reader: source, + reader: source!, pathMapping: { linkPath: "/wow/this/is/a/beautiful/path/just/wow/", targetPath: "/resources/", From a14b3519b1cdd339923d7af1b3e05939457465b4 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 17:01:14 +0300 Subject: [PATCH 50/69] refactor: AbstractAdapter test --- src/utils/mock-projects.d.ts | 1 + test/lib/adapters/AbstractAdapter.ts | 49 ++++++++++++++-------------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/utils/mock-projects.d.ts b/src/utils/mock-projects.d.ts index 7c72379e..60219504 100644 --- a/src/utils/mock-projects.d.ts +++ b/src/utils/mock-projects.d.ts @@ -5,6 +5,7 @@ declare module "@ui5/project/specifications/Project" { export interface Project { getName: () => string; + getVersion: () => string; getType: () => "project" | "application" | "library"; } } diff --git a/test/lib/adapters/AbstractAdapter.ts b/test/lib/adapters/AbstractAdapter.ts index d0842f7f..d0822a11 100644 --- a/test/lib/adapters/AbstractAdapter.ts +++ b/test/lib/adapters/AbstractAdapter.ts @@ -2,12 +2,13 @@ import test from "ava"; import AbstractAdapter from "../../../src/adapters/AbstractAdapter.js"; import {createResource} from "../../../src/resourceFactory.js"; import {LegacyResource} from "../../../src/Resource.js"; +import {Project} from "@ui5/project/specifications/Project"; class MyAbstractAdapter extends AbstractAdapter { } test("Missing paramter: virBasePath", (t) => { t.throws(() => { - new MyAbstractAdapter({}); + new MyAbstractAdapter({} as {virBasePath: string; excludes?: string[]; project?: Project}); }, { message: "Unable to create adapter: Missing parameter 'virBasePath'", }, "Threw with expected error message"); @@ -54,7 +55,7 @@ test("_assignProjectToResource: Resource is already assigned to another project project: { getName: () => "test.lib", getVersion: () => "2.0.0", - }, + } as Project, }); const writer = new MyAbstractAdapter({ @@ -62,7 +63,7 @@ test("_assignProjectToResource: Resource is already assigned to another project project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); const error = t.throws(() => writer._assignProjectToResource(resource)); @@ -76,7 +77,7 @@ test("_isPathHandled", (t) => { project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.true(writer._isPathHandled("/dest2/writer/test.js"), "Returned expected result"); @@ -92,7 +93,7 @@ test("_resolveVirtualPathToBase (read mode)", (t) => { project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.is(writer._resolveVirtualPathToBase("/dest2/writer/test.js"), "test.js", "Returned expected path"); @@ -108,7 +109,7 @@ test("_resolveVirtualPathToBase (read mode): Path does not starting with path co project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.is(writer._resolveVirtualPathToBase("/dest2/tmp/test.js"), null, "Returned null"); @@ -123,7 +124,7 @@ test("_resolveVirtualPathToBase (read mode): Path Must be absolute", (t) => { project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.throws(() => writer._resolveVirtualPathToBase("./dest2/write"), { @@ -138,7 +139,7 @@ test("_resolveVirtualPathToBase (write mode)", (t) => { project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.is(writer._resolveVirtualPathToBase("/dest2/writer/test.js", true), "test.js", "Returned expected path"); @@ -155,7 +156,7 @@ test("_resolveVirtualPathToBase (write mode): Path does not starting with path c project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.throws(() => writer._resolveVirtualPathToBase("/dest2/tmp/test.js", true), { @@ -189,7 +190,7 @@ test("_resolveVirtualPathToBase (write mode): Path Must be absolute", (t) => { project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.throws(() => writer._resolveVirtualPathToBase("./dest2/write", true), { @@ -198,44 +199,44 @@ test("_resolveVirtualPathToBase (write mode): Path Must be absolute", (t) => { }, "Threw with expected error message"); }); -test("_normalizePattern", async (t) => { +test("_normalizePattern", (t) => { const writer = new MyAbstractAdapter({ virBasePath: "/path/", project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); - t.deepEqual(await writer._normalizePattern("/*/{src,test}/**"), [ + t.deepEqual(writer._normalizePattern("/*/{src,test}/**"), [ "src/**", "test/**", ], "Returned expected patterns"); }); -test("_normalizePattern: Match base directory", async (t) => { +test("_normalizePattern: Match base directory", (t) => { const writer = new MyAbstractAdapter({ virBasePath: "/path/", project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); - t.deepEqual(await writer._normalizePattern("/*"), [""], + t.deepEqual(writer._normalizePattern("/*"), [""], "Returned an empty pattern since the input pattern matches the base directory only"); }); -test("_normalizePattern: Match sub-directory", async (t) => { +test("_normalizePattern: Match sub-directory", (t) => { const writer = new MyAbstractAdapter({ virBasePath: "/path/", project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); - t.deepEqual(await writer._normalizePattern("/path/*"), ["*"], + t.deepEqual(writer._normalizePattern("/path/*"), ["*"], "Returned expected patterns"); }); @@ -245,7 +246,7 @@ test("_normalizePattern: Match all", (t) => { project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.deepEqual(writer._normalizePattern("/**/*"), ["**/*"], @@ -258,7 +259,7 @@ test("_normalizePattern: Relative path segment above virtual root directory", (t project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.deepEqual(writer._normalizePattern("/path/../../*"), [], @@ -271,7 +272,7 @@ test("_normalizePattern: Relative path segment resolving to base directory", (t) project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.deepEqual(writer._normalizePattern("/*/../*"), [""], @@ -284,7 +285,7 @@ test("_normalizePattern: Relative path segment", (t) => { project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.deepEqual(writer._normalizePattern("/path/../*"), [""], @@ -297,7 +298,7 @@ test("_normalizePattern: Relative path segment within base directory, matching a project: { getName: () => "test.lib1", getVersion: () => "2.0.0", - }, + } as Project, }); t.deepEqual(writer._normalizePattern("/path/path2/../**/*"), ["**/*"], From b2ad4be32fbda6193ac30eefc04bffdc53ae86c4 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 17:13:07 +0300 Subject: [PATCH 51/69] refactor: Migrate ResourceTagCollection tests --- src/ResourceTagCollection.ts | 11 ++++++----- test/lib/ResourceTagCollection.ts | 6 +++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/ResourceTagCollection.ts b/src/ResourceTagCollection.ts index dde4dc66..48b57b8a 100644 --- a/src/ResourceTagCollection.ts +++ b/src/ResourceTagCollection.ts @@ -26,7 +26,7 @@ class ResourceTagCollection { _allowedNamespacesRegExp: null | RegExp; constructor({allowedTags = [], allowedNamespaces = [], tags}: - {allowedTags: string[]; allowedNamespaces: string[]; tags: PathTagsInterface}) { + {allowedTags?: string[]; allowedNamespaces?: string[]; tags?: PathTagsInterface}) { this._allowedTags = allowedTags; // Allowed tags are validated during use this._allowedNamespaces = allowedNamespaces; @@ -45,10 +45,10 @@ class ResourceTagCollection { this._allowedNamespacesRegExp = null; } - this._pathTags = tags || Object.create(null); + this._pathTags = tags ?? Object.create(null) as PathTagsInterface; } - setTag(resourcePath: string, tag: string, value: string | number | boolean = true) { + setTag(resourcePath: ResourceInterface | string, tag: string, value: string | number | boolean = true) { resourcePath = this._getPath(resourcePath); this._validateTag(tag); this._validateValue(value); @@ -63,7 +63,7 @@ class ResourceTagCollection { } } - clearTag(resourcePath: string, tag: string) { + clearTag(resourcePath: ResourceInterface | string, tag: string) { resourcePath = this._getPath(resourcePath); this._validateTag(tag); @@ -73,7 +73,8 @@ class ResourceTagCollection { } } - getTag(resourcePath: string, tag: string): string | number | boolean | undefined | PathTagsInterface { + getTag(resourcePath: ResourceInterface | string, + tag: string): string | number | boolean | undefined | PathTagsInterface { resourcePath = this._getPath(resourcePath); this._validateTag(tag); diff --git a/test/lib/ResourceTagCollection.ts b/test/lib/ResourceTagCollection.ts index a457f20a..cf1d8093 100644 --- a/test/lib/ResourceTagCollection.ts +++ b/test/lib/ResourceTagCollection.ts @@ -3,7 +3,7 @@ import sinon from "sinon"; import Resource from "../../src/Resource.js"; import ResourceTagCollection from "../../src/ResourceTagCollection.js"; -test.afterEach.always((t) => { +test.afterEach.always(() => { sinon.restore(); }); @@ -282,6 +282,7 @@ test("_validateValue: Invalid value of type object", (t) => { allowedTags: ["abc:MyTag"], }); t.throws(() => { + // @ts-expect-error testing invalid value tagCollection._validateValue({foo: "bar"}); }, { instanceOf: Error, @@ -294,6 +295,7 @@ test("_validateValue: Invalid value undefined", (t) => { allowedTags: ["abc:MyTag"], }); t.throws(() => { + // @ts-expect-error testing invalid value tagCollection._validateValue(undefined); }, { instanceOf: Error, @@ -306,6 +308,7 @@ test("_validateValue: Invalid value null", (t) => { allowedTags: ["abc:MyTag"], }); t.throws(() => { + // @ts-expect-error testing invalid value tagCollection._validateValue(null); }, { instanceOf: Error, @@ -318,6 +321,7 @@ test("_getPath: Empty path", (t) => { allowedTags: ["abc:MyTag"], }); t.throws(() => { + // @ts-expect-error testing invalid value tagCollection._getPath({ getPath: () => "", }); From 1c9a8818ca9f320458124075ff227da67035a039 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 17:23:50 +0300 Subject: [PATCH 52/69] refactor: ResourceFacade tests --- test/lib/ResourceFacade.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/lib/ResourceFacade.ts b/test/lib/ResourceFacade.ts index 2d57b34a..7dd222c7 100644 --- a/test/lib/ResourceFacade.ts +++ b/test/lib/ResourceFacade.ts @@ -1,9 +1,9 @@ import test from "ava"; import sinon from "sinon"; -import Resource from "../../src/Resource.js"; +import Resource, {ResourceInterface} from "../../src/Resource.js"; import ResourceFacade from "../../src/ResourceFacade.js"; -test.afterEach.always((t) => { +test.afterEach.always(() => { sinon.restore(); }); @@ -23,6 +23,7 @@ test("Create instance", (t) => { test("Create instance: Missing parameters", (t) => { t.throws(() => { + // @ts-expect-error testing missing arguments new ResourceFacade({ path: "/my/path", }); @@ -32,6 +33,7 @@ test("Create instance: Missing parameters", (t) => { }); t.throws(() => { new ResourceFacade({ + // @ts-expect-error testing missing arguments resource: {}, }); }, { @@ -72,7 +74,7 @@ test("ResourceFacade #setPath", (t) => { }); test("ResourceFacade provides same public functions as Resource", (t) => { - const resource = new Resource({ + const resource: ResourceInterface = new Resource({ path: "/my/path/to/resource", string: "my content", }); @@ -82,15 +84,17 @@ test("ResourceFacade provides same public functions as Resource", (t) => { }); const methods = Object.getOwnPropertyNames(Resource.prototype) - .filter((p) => (!p.startsWith("_") && typeof resource[p] === "function")); + .filter((p) => (!p.startsWith("_") && typeof resource[p as keyof typeof resource] === "function")); methods.forEach((method) => { - t.truthy(resourceFacade[method], `resourceFacade provides function #${method}`); + t.truthy(method in resourceFacade, `resourceFacade provides function #${method}`); if (["constructor", "getPath", "getName", "setPath", "clone"].includes(method)) { // special functions with separate tests return; } + // @ts-expect-error Stubbing the resource const stub = sinon.stub(resource, method); + // @ts-expect-error Checking stubbed resource resourceFacade[method]("argument"); t.is(stub.callCount, 1, `Resource#${method} stub got called once by resourceFacade#${method}`); stub.restore(); From f3b667dbf68601b5cf4d70c775fffe368712fe95 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 17:34:09 +0300 Subject: [PATCH 53/69] refactor: Migrate Resource test --- test/lib/Resource.ts | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/test/lib/Resource.ts b/test/lib/Resource.ts index f79c5b29..9280eddd 100644 --- a/test/lib/Resource.ts +++ b/test/lib/Resource.ts @@ -1,8 +1,9 @@ import test from "ava"; -import {Stream, Transform} from "node:stream"; +import {Stream, Transform, Readable} from "node:stream"; import {promises as fs, createReadStream} from "node:fs"; import path from "node:path"; import Resource from "../../src/Resource.js"; +import {Project} from "@ui5/project/specifications/Project"; function createBasicResource() { const fsPath = path.join("test", "fixtures", "application.a", "webapp", "index.html"); @@ -11,9 +12,8 @@ function createBasicResource() { createStream: function () { return createReadStream(fsPath); }, - project: {}, + project: {} as Project, statInfo: {}, - fsPath, }); return resource; } @@ -24,16 +24,16 @@ function createBasicResource() { * @param {stream.Readable} readableStream readable stream * @returns {Promise} resolves with the read string */ -const readStream = (readableStream) => { +const readStream = (readableStream: Readable) => { return new Promise((resolve, reject) => { let streamedResult = ""; - readableStream.on("data", (chunk) => { + readableStream.on("data", (chunk: string) => { streamedResult += chunk; }); readableStream.on("end", () => { resolve(streamedResult); }); - readableStream.on("error", (err) => { + readableStream.on("error", (err: Error) => { reject(err); }); }); @@ -41,6 +41,7 @@ const readStream = (readableStream) => { test("Resource: constructor with missing path parameter", (t) => { t.throws(() => { + // @ts-expect-error testing missing arguments new Resource({}); }, { instanceOf: Error, @@ -175,6 +176,7 @@ test("Resource: Illegal source metadata attribute", (t) => { sourceMetadata: { adapter: "My Adapter", fsPath: "/some/path", + // @ts-expect-error testing invalid value pony: "🦄", }, }); @@ -188,6 +190,7 @@ test("Resource: Illegal source metadata value", (t) => { new Resource({ path: "/my/path", string: "Content", + // @ts-expect-error testing invalid value sourceMetadata: { adapter: "My Adapter", fsPath: { @@ -287,7 +290,7 @@ test("Resource: getStream for empty string instance", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", - string: new String(""), + string: new String("") as string, }); const result = await readStream(resource.getStream()); @@ -385,6 +388,7 @@ test("Resource: size modification", async (t) => { path: "/my/path/to/resource", }); const stream = new Stream.Readable(); + // eslint-disable-next-line @typescript-eslint/no-empty-function stream._read = function () {}; stream.push("I am a "); stream.push("readable "); @@ -411,6 +415,7 @@ test("Resource: setStream (Stream)", async (t) => { t.false(resource.isModified(), "Resource is not modified"); const stream = new Stream.Readable(); + // eslint-disable-next-line @typescript-eslint/no-empty-function stream._read = function () {}; stream.push("I am a "); stream.push("readable "); @@ -437,6 +442,7 @@ test("Resource: setStream (Create stream callback)", async (t) => { resource.setStream(() => { const stream = new Stream.Readable(); + // eslint-disable-next-line @typescript-eslint/no-empty-function stream._read = function () {}; stream.push("I am a "); stream.push("readable "); @@ -474,6 +480,7 @@ test("Resource: clone resource with stream", async (t) => { path: "/my/path/to/resource", }); const stream = new Stream.Readable(); + // eslint-disable-next-line @typescript-eslint/no-empty-function stream._read = function () {}; stream.push("Content"); stream.push(null); @@ -531,13 +538,13 @@ test("Resource: clone resource with project removes project", async (t) => { const resource = new Resource({ path: "/my/path/to/resource", - project: myProject, + project: myProject as unknown as Project, }); const clonedResource = await resource.clone(); t.pass("Resource cloned"); - const clonedResourceProject = await clonedResource.getProject(); + const clonedResourceProject = clonedResource.getProject(); t.falsy(clonedResourceProject, "Cloned resource should not have a project"); }); @@ -626,10 +633,10 @@ test("Resource: getProject", (t) => { t.plan(1); const resource = new Resource({ path: "/my/path/to/resource", - project: {getName: () => "Mock Project"}, + project: {getName: () => "Mock Project"} as Project, }); const project = resource.getProject(); - t.is(project.getName(), "Mock Project"); + t.is(project!.getName(), "Mock Project"); }); test("Resource: setProject", (t) => { @@ -637,18 +644,18 @@ test("Resource: setProject", (t) => { const resource = new Resource({ path: "/my/path/to/resource", }); - const project = {getName: () => "Mock Project"}; + const project = {getName: () => "Mock Project"} as Project; resource.setProject(project); - t.is(resource.getProject().getName(), "Mock Project"); + t.is(resource.getProject()!.getName(), "Mock Project"); }); test("Resource: reassign with setProject", (t) => { t.plan(2); const resource = new Resource({ path: "/my/path/to/resource", - project: {getName: () => "Mock Project"}, + project: {getName: () => "Mock Project"} as Project, }); - const project = {getName: () => "New Mock Project"}; + const project = {getName: () => "New Mock Project"} as Project; const error = t.throws(() => resource.setProject(project)); t.is(error.message, "Unable to assign project New Mock Project to resource /my/path/to/resource: " + "Resource is already associated to project Mock Project"); @@ -656,6 +663,7 @@ test("Resource: reassign with setProject", (t) => { test("Resource: constructor with stream", async (t) => { const stream = new Stream.Readable(); + // eslint-disable-next-line @typescript-eslint/no-empty-function stream._read = function () {}; stream.push("I am a "); stream.push("readable "); From beb96ffb6c0a1e4e7d37bd2387d964384e4a4384 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 17:36:43 +0300 Subject: [PATCH 54/69] refactor: AbstractReaderWriter tests --- test/lib/AbstractReaderWriter.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/lib/AbstractReaderWriter.ts b/test/lib/AbstractReaderWriter.ts index 7ca55b67..a81b9a0e 100644 --- a/test/lib/AbstractReaderWriter.ts +++ b/test/lib/AbstractReaderWriter.ts @@ -16,7 +16,8 @@ test("Incomplete AbstractReaderWriter subclass: Abstract functions throw error", const instance = new Dummy(); t.throws(() => { - instance._write(); + // @ts-expect-error testing invalid value + void instance._write(); }, { instanceOf: Error, message: "Not implemented", From fcb0b311d88fec8c572d53d182bffd37d175c142 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 17:39:14 +0300 Subject: [PATCH 55/69] refactor: Remove module aliases --- src/AbstractReader.ts | 2 -- src/AbstractReaderWriter.ts | 2 -- src/DuplexCollection.ts | 2 -- src/ReaderCollection.ts | 2 -- src/ReaderCollectionPrioritized.ts | 2 -- src/Resource.ts | 2 -- src/ResourceFacade.ts | 2 -- src/ResourceTagCollection.ts | 2 -- src/WriterCollection.ts | 2 -- src/adapters/AbstractAdapter.ts | 2 -- src/adapters/FileSystem.ts | 2 -- src/adapters/Memory.ts | 5 ++--- src/readers/Filter.ts | 2 -- src/readers/Link.ts | 2 -- 14 files changed, 2 insertions(+), 29 deletions(-) diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index 714bb6a0..aab6dc31 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -4,8 +4,6 @@ import {ResourceInterface} from "./Resource.js"; /** * Abstract resource locator implementing the general API for reading resources - * - * @alias @ui5/fs/AbstractReader */ class AbstractReader { _name: string | undefined; diff --git a/src/AbstractReaderWriter.ts b/src/AbstractReaderWriter.ts index de30031d..fb7665e0 100644 --- a/src/AbstractReaderWriter.ts +++ b/src/AbstractReaderWriter.ts @@ -3,8 +3,6 @@ import {ResourceInterface} from "./Resource.js"; /** * Abstract resource locator implementing the general API for reading and writing resources - * - * @alias @ui5/fs/AbstractReaderWriter */ class AbstractReaderWriter extends AbstractReader { /** diff --git a/src/DuplexCollection.ts b/src/DuplexCollection.ts index 6ab2215a..b1363bfc 100644 --- a/src/DuplexCollection.ts +++ b/src/DuplexCollection.ts @@ -6,8 +6,6 @@ import Trace from "./tracing/Trace.js"; /** * Wrapper to keep readers and writers together - * - * @alias @ui5/fs/DuplexCollection */ class DuplexCollection extends AbstractReaderWriter { _reader: AbstractReader; diff --git a/src/ReaderCollection.ts b/src/ReaderCollection.ts index 53a5f5fd..100fe7f3 100644 --- a/src/ReaderCollection.ts +++ b/src/ReaderCollection.ts @@ -4,8 +4,6 @@ import Trace from "./tracing/Trace.js"; /** * Resource Locator ReaderCollection - * - * @alias @ui5/fs/ReaderCollection */ class ReaderCollection extends AbstractReader { _readers: AbstractReader[]; diff --git a/src/ReaderCollectionPrioritized.ts b/src/ReaderCollectionPrioritized.ts index ae136955..e185e325 100644 --- a/src/ReaderCollectionPrioritized.ts +++ b/src/ReaderCollectionPrioritized.ts @@ -4,8 +4,6 @@ import Trace from "./tracing/Trace.js"; /** * Prioritized Resource Locator Collection - * - * @alias @ui5/fs/ReaderCollectionPrioritized */ class ReaderCollectionPrioritized extends AbstractReader { _readers: AbstractReader[]; diff --git a/src/Resource.ts b/src/Resource.ts index 7a9a08ae..9e848eaf 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -84,8 +84,6 @@ export interface ResourceInterface { } /** * Resource. UI5 Tooling specific representation of a file's content and metadata - * - * @alias @ui5/fs/Resource */ class Resource implements ResourceInterface { #project; diff --git a/src/ResourceFacade.ts b/src/ResourceFacade.ts index 7adbe111..403cdfee 100644 --- a/src/ResourceFacade.ts +++ b/src/ResourceFacade.ts @@ -6,8 +6,6 @@ import {Project} from "@ui5/project/specifications/Project"; /** * A {@link @ui5/fs/Resource Resource} with a different path than it's original - * - * @alias @ui5/fs/ResourceFacade */ class ResourceFacade implements ResourceInterface { #path; diff --git a/src/ResourceTagCollection.ts b/src/ResourceTagCollection.ts index 48b57b8a..f9be3eb1 100644 --- a/src/ResourceTagCollection.ts +++ b/src/ResourceTagCollection.ts @@ -16,8 +16,6 @@ export function isPathTagsInterface(elem: unknown): elem is PathTagsInterface { /** * A ResourceTagCollection - * - * @alias @ui5/fs/internal/ResourceTagCollection */ class ResourceTagCollection { _allowedTags: string[]; diff --git a/src/WriterCollection.ts b/src/WriterCollection.ts index cced9e7b..ca506369 100644 --- a/src/WriterCollection.ts +++ b/src/WriterCollection.ts @@ -6,8 +6,6 @@ import {ResourceInterface} from "./Resource.js"; /** * Resource Locator WriterCollection - * - * @alias @ui5/fs/WriterCollection */ class WriterCollection extends AbstractReaderWriter { _basePathRegex: string; diff --git a/src/adapters/AbstractAdapter.ts b/src/adapters/AbstractAdapter.ts index 26afc3e2..894cefc5 100644 --- a/src/adapters/AbstractAdapter.ts +++ b/src/adapters/AbstractAdapter.ts @@ -11,8 +11,6 @@ import {isMigratedResource} from "../utils/tsUtils.js"; /** * Abstract Resource Adapter - * - * @alias @ui5/fs/adapters/AbstractAdapter */ class AbstractAdapter extends AbstractReaderWriter { _virBasePath: string; diff --git a/src/adapters/FileSystem.ts b/src/adapters/FileSystem.ts index c78d9f12..3e4ba7bd 100644 --- a/src/adapters/FileSystem.ts +++ b/src/adapters/FileSystem.ts @@ -18,8 +18,6 @@ const READ_ONLY_MODE = 0o444; const ADAPTER_NAME = "FileSystem"; /** * File system resource adapter - * - * @alias @ui5/fs/adapters/FileSystem */ class FileSystem extends AbstractAdapter { _fsBasePath: string; diff --git a/src/adapters/Memory.ts b/src/adapters/Memory.ts index a636bc3e..bfc63e5e 100644 --- a/src/adapters/Memory.ts +++ b/src/adapters/Memory.ts @@ -10,8 +10,6 @@ const ADAPTER_NAME = "Memory"; /** * Virtual resource Adapter - * - * @alias @ui5/fs/adapters/Memory */ class Memory extends AbstractAdapter { _virFiles: Record; @@ -39,7 +37,8 @@ class Memory extends AbstractAdapter { * @param resourceMap Resources cache * @returns */ - async _matchPatterns(patterns: string[], resourceMap: Record): Promise { + async _matchPatterns(patterns: string[], + resourceMap: Record): Promise { const resourcePaths = Object.keys(resourceMap); const matchedPaths = micromatch(resourcePaths, patterns, { dot: true, diff --git a/src/readers/Filter.ts b/src/readers/Filter.ts index 48461b44..482dc757 100644 --- a/src/readers/Filter.ts +++ b/src/readers/Filter.ts @@ -17,8 +17,6 @@ export interface Filter_Params { /** * A reader that allows dynamic filtering of resources passed through it - * - * @alias @ui5/fs/readers/Filter */ class Filter extends AbstractReader { _reader: AbstractReader; diff --git a/src/readers/Link.ts b/src/readers/Link.ts index 99d4e5f4..07d7acd8 100644 --- a/src/readers/Link.ts +++ b/src/readers/Link.ts @@ -29,8 +29,6 @@ export interface Link_Args { * // The following resolves with a @ui5/fs/ResourceFacade of the resource * // located at "/resources/my-app-name/Component.js" in the sourceReader * const resource = await linkedReader.byPath("/app/Component.js"); - * - * @alias @ui5/fs/readers/Link */ class Link extends AbstractReader { _reader: AbstractReader; From 24604dd4630c117d40a1018aaa9494d2544d3929 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 17:41:59 +0300 Subject: [PATCH 56/69] fix: Tests --- test/lib/AbstractReader.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/lib/AbstractReader.ts b/test/lib/AbstractReader.ts index 0e9a5b1f..1945ae51 100644 --- a/test/lib/AbstractReader.ts +++ b/test/lib/AbstractReader.ts @@ -10,25 +10,28 @@ test("AbstractReader: constructor throws an error", (t) => { }); }); -test("Incomplete AbstractReader subclass: Abstract functions throw error", (t) => { +test("Incomplete AbstractReader subclass: Abstract functions throw error", async (t) => { class Dummy extends AbstractReader {} const instance = new Dummy(); - t.throws(async () => { + await t.throwsAsync(async () => { + // @ts-expect-error testing invalid value await instance._byGlob(); }, { instanceOf: Error, message: "Function '_byGlob' is not implemented", }); - t.throws(async () => { + await t.throwsAsync(async () => { + // @ts-expect-error testing invalid value await instance._runGlob(); }, { instanceOf: Error, message: "Function '_runGlob' is not implemented", }); - t.throws(async () => { + await t.throwsAsync(async () => { + // @ts-expect-error testing invalid value await instance._byPath(); }, { instanceOf: Error, From c1ec81dc00bc1a2f7a5313b82f5a167b2f03d0a8 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 17:47:56 +0300 Subject: [PATCH 57/69] fix: JSDoc generation script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a3e59084..aa42d2d0 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "coverage": "rimraf test/tmp && nyc ava --node-arguments=\"--experimental-loader=@istanbuljs/esm-loader-hook\"", "coverage-xunit": "nyc --reporter=text --reporter=text-summary --reporter=cobertura npm run unit-xunit", "jsdoc": "npm run jsdoc-generate && open-cli jsdocs/index.html", - "jsdoc-generate": "jsdoc -c ./jsdoc.json -t $(node -p 'path.dirname(require.resolve(\"docdash\"))') ./lib/ || (echo 'Error during JSDoc generation! Check log.' && exit 1)", + "jsdoc-generate": "npm run build && jsdoc -c ./jsdoc.json -t $(node -p 'path.dirname(require.resolve(\"docdash\"))') ./lib/ || (echo 'Error during JSDoc generation! Check log.' && exit 1)", "jsdoc-watch": "npm run jsdoc && chokidar \"./lib/**/*.js\" -c \"npm run jsdoc-generate\"", "preversion": "npm test", "version": "git-chglog --sort semver --next-tag v$npm_package_version -o CHANGELOG.md v4.0.0.. && git add CHANGELOG.md", From 5276119fc9d7b6f551b2cecb80b30cd97c771351 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 17:48:16 +0300 Subject: [PATCH 58/69] fix: tsc build issues --- src/AbstractReader.ts | 2 +- src/adapters/AbstractAdapter.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index aab6dc31..a3996ac7 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -43,7 +43,7 @@ class AbstractReader { * @returns Promise resolving to list of resources */ byGlob(virPattern: string | string[], options = {nodir: true}): Promise { - const trace = new Trace(virPattern); + const trace = new Trace(Array.isArray(virPattern) ? virPattern.join("") : virPattern); return this._byGlob(virPattern, options, trace).then(function (result: ResourceInterface[]) { trace.printReport(); return result; diff --git a/src/adapters/AbstractAdapter.ts b/src/adapters/AbstractAdapter.ts index 894cefc5..1107ca26 100644 --- a/src/adapters/AbstractAdapter.ts +++ b/src/adapters/AbstractAdapter.ts @@ -147,7 +147,7 @@ class AbstractAdapter extends AbstractReaderWriter { log.verbose(`Virtual base path: ${this._virBaseDir}`); log.verbose(`Pattern to match: ${virPattern}`); log.verbose(`Current subset (tried index ${i}):`); - log.verbose(subset); + log.verbose(String(subset)); return {idx: i, virtualMatch: true}; } const basePathPart = basePathParts[i]; @@ -270,7 +270,7 @@ class AbstractAdapter extends AbstractReaderWriter { } return null; } - if (this._isPathExcluded(virPath)) { + if (this._isPathExcluded(Array.isArray(virPath) ? virPath : [virPath])) { if (log.isLevelEnabled("silly")) { log.silly(`Failed to resolve virtual path '${inputVirPath}': ` + `Resolved path is excluded by configuration of adapter with base path '${this._virBasePath}'`); From 494d7114ffdbcb34e96760c25364d16c0e8332d5 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Wed, 28 Aug 2024 16:52:38 +0200 Subject: [PATCH 59/69] [INTERNAL] TypeScript: Emit types --- tsconfig.base.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tsconfig.base.json b/tsconfig.base.json index d4d68beb..02c658af 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -7,5 +7,7 @@ "lib": ["ES2022"], "strict": true, "sourceMap": true, + "declaration": true, + "declarationMap": true, } } From f9431e482cb5063376f314bfe0283a4b91b70008 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 17:53:45 +0300 Subject: [PATCH 60/69] refactor: Switch jsdoc generation to typedoc --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index aa42d2d0..c786fe72 100644 --- a/package.json +++ b/package.json @@ -52,8 +52,8 @@ "coverage": "rimraf test/tmp && nyc ava --node-arguments=\"--experimental-loader=@istanbuljs/esm-loader-hook\"", "coverage-xunit": "nyc --reporter=text --reporter=text-summary --reporter=cobertura npm run unit-xunit", "jsdoc": "npm run jsdoc-generate && open-cli jsdocs/index.html", - "jsdoc-generate": "npm run build && jsdoc -c ./jsdoc.json -t $(node -p 'path.dirname(require.resolve(\"docdash\"))') ./lib/ || (echo 'Error during JSDoc generation! Check log.' && exit 1)", - "jsdoc-watch": "npm run jsdoc && chokidar \"./lib/**/*.js\" -c \"npm run jsdoc-generate\"", + "jsdoc-generate": "typedoc", + "jsdoc-watch": "typedoc --watch", "preversion": "npm test", "version": "git-chglog --sort semver --next-tag v$npm_package_version -o CHANGELOG.md v4.0.0.. && git add CHANGELOG.md", "prepublishOnly": "git push --follow-tags", From d21d2ec41f7482deab46c375770d589fc3cf5e50 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 28 Aug 2024 17:59:18 +0300 Subject: [PATCH 61/69] fix: Resolve merge conflicts --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c786fe72..629f41a4 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "random-int": "^3.0.0" }, "devDependencies": { - "@eslint/js": "^9.9.0", + "@eslint/js": "^9.9.1", "@istanbuljs/esm-loader-hook": "^0.2.0", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@stylistic/eslint-plugin": "^2.6.4", From 4ee03fa7b81aef8cded6a826e760aa046eca6b96 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Wed, 28 Aug 2024 18:43:02 +0200 Subject: [PATCH 62/69] [INTERNAL] TypeScript/ESLint: Allow missing jsdoc, require consistend type import/export --- eslint.common.config.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/eslint.common.config.js b/eslint.common.config.js index bc354835..f6284f68 100644 --- a/eslint.common.config.js +++ b/eslint.common.config.js @@ -62,6 +62,12 @@ export default tseslint.config( // TypeScript specific overwrites // We must disable the base rule as it can report incorrect errors "no-unused-vars": "off", + "@typescript-eslint/consistent-type-imports": ["error", { + fixStyle: "inline-type-imports", + }], + "@typescript-eslint/consistent-type-exports": ["error", { + fixMixedExportsWithInlineTypeSpecifier: true, + }], "@typescript-eslint/no-unused-vars": [ "error", { argsIgnorePattern: "^_", @@ -120,7 +126,7 @@ export default tseslint.config( "no-console": "error", "no-eval": "error", - "valid-jsdoc": 0, + "valid-jsdoc": "off", }, }, { // JSdoc only applying to sources @@ -130,9 +136,10 @@ export default tseslint.config( // Overwriting JSDoc rules in a separate config with the same files pattern files: ["src/**/*.ts"], rules: { - "jsdoc/require-returns": 0, - "jsdoc/require-returns-description": 0, - "jsdoc/tag-lines": [2, "any", { + "jsdoc/require-jsdoc": "off", + "jsdoc/require-returns": "off", + "jsdoc/require-returns-description": "off", + "jsdoc/tag-lines": ["error", "any", { startLines: 1, }], }, From a3963f3f04df08f918dc962004e6d2ab3c50b0cb Mon Sep 17 00:00:00 2001 From: Max Reichmann Date: Thu, 29 Aug 2024 10:13:11 +0200 Subject: [PATCH 63/69] refactor: Fix ESLint errors in /test/lib/ --- test/lib/Resource.ts | 4 ++-- test/lib/ResourceFacade.ts | 2 +- test/lib/adapters/AbstractAdapter.ts | 4 ++-- test/lib/resources.ts | 2 +- test/lib/tracing/traceSummary.ts | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/lib/Resource.ts b/test/lib/Resource.ts index 9280eddd..2c09da42 100644 --- a/test/lib/Resource.ts +++ b/test/lib/Resource.ts @@ -1,9 +1,9 @@ import test from "ava"; -import {Stream, Transform, Readable} from "node:stream"; +import {Stream, Transform, type Readable} from "node:stream"; import {promises as fs, createReadStream} from "node:fs"; import path from "node:path"; import Resource from "../../src/Resource.js"; -import {Project} from "@ui5/project/specifications/Project"; +import {type Project} from "@ui5/project/specifications/Project"; function createBasicResource() { const fsPath = path.join("test", "fixtures", "application.a", "webapp", "index.html"); diff --git a/test/lib/ResourceFacade.ts b/test/lib/ResourceFacade.ts index 7dd222c7..ebf4e274 100644 --- a/test/lib/ResourceFacade.ts +++ b/test/lib/ResourceFacade.ts @@ -1,6 +1,6 @@ import test from "ava"; import sinon from "sinon"; -import Resource, {ResourceInterface} from "../../src/Resource.js"; +import Resource, {type ResourceInterface} from "../../src/Resource.js"; import ResourceFacade from "../../src/ResourceFacade.js"; test.afterEach.always(() => { diff --git a/test/lib/adapters/AbstractAdapter.ts b/test/lib/adapters/AbstractAdapter.ts index d0822a11..e4758e08 100644 --- a/test/lib/adapters/AbstractAdapter.ts +++ b/test/lib/adapters/AbstractAdapter.ts @@ -1,8 +1,8 @@ import test from "ava"; import AbstractAdapter from "../../../src/adapters/AbstractAdapter.js"; import {createResource} from "../../../src/resourceFactory.js"; -import {LegacyResource} from "../../../src/Resource.js"; -import {Project} from "@ui5/project/specifications/Project"; +import {type LegacyResource} from "../../../src/Resource.js"; +import {type Project} from "@ui5/project/specifications/Project"; class MyAbstractAdapter extends AbstractAdapter { } diff --git a/test/lib/resources.ts b/test/lib/resources.ts index 2a76e96c..35b5ae77 100644 --- a/test/lib/resources.ts +++ b/test/lib/resources.ts @@ -12,7 +12,7 @@ import {readFile} from "node:fs/promises"; import {createAdapter, createFilterReader, createFlatReader, createLinkReader, createResource} from "../../src/resourceFactory.js"; -import {Project} from "@ui5/project/specifications/Project"; +import {type Project} from "@ui5/project/specifications/Project"; test.afterEach.always(() => { sinon.restore(); diff --git a/test/lib/tracing/traceSummary.ts b/test/lib/tracing/traceSummary.ts index 0ab8f175..96428a40 100644 --- a/test/lib/tracing/traceSummary.ts +++ b/test/lib/tracing/traceSummary.ts @@ -1,6 +1,6 @@ -import anyTest, {TestFn, ExecutionContext} from "ava"; -import sinon, {SinonStub} from "sinon"; -import esmock, {MockFunction} from "esmock"; +import anyTest, {type TestFn, type ExecutionContext} from "ava"; +import sinon, {type SinonStub} from "sinon"; +import esmock, {type MockFunction} from "esmock"; interface avaContext { loggerStub: { From c5a02c0f8a9fff4127d70a8477d60acf00a4f692 Mon Sep 17 00:00:00 2001 From: Max Reichmann Date: Thu, 29 Aug 2024 10:15:24 +0200 Subject: [PATCH 64/69] refactor: Update package-lock.json --- package-lock.json | 1301 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 1207 insertions(+), 94 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7ee84c93..6928a1ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,15 +20,21 @@ "random-int": "^3.0.0" }, "devDependencies": { - "@eslint/js": "^9.8.0", + "@eslint/js": "^9.9.1", "@istanbuljs/esm-loader-hook": "^0.2.0", + "@istanbuljs/nyc-config-typescript": "^1.0.2", + "@stylistic/eslint-plugin": "^2.6.4", + "@types/clone": "^2.1.4", + "@types/micromatch": "^4.0.9", + "@types/node": "^20.11.0", + "@types/pretty-hrtime": "^1.0.3", + "@types/sinon": "^17.0.3", "ava": "^6.1.3", "chokidar-cli": "^3.0.0", "cross-env": "^7.0.3", "depcheck": "^1.4.7", "docdash": "^2.0.2", - "eslint": "^9.9.1", - "eslint-config-google": "^0.14.0", + "eslint": "^9.9.0", "eslint-plugin-ava": "^15.0.1", "eslint-plugin-jsdoc": "^50.2.2", "esmock": "^2.6.7", @@ -38,7 +44,11 @@ "open-cli": "^8.0.0", "rimraf": "^6.0.1", "sinon": "^18.0.0", - "tap-xunit": "^2.4.1" + "tap-xunit": "^2.4.1", + "tsx": "^4.17.0", + "typedoc": "^0.26.6", + "typedoc-plugin-rename-defaults": "^0.7.1", + "typescript-eslint": "^8.2.0" }, "engines": { "node": "^20.11.0 || >=22.0.0", @@ -333,6 +343,414 @@ "node": ">=16" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -613,6 +1031,22 @@ "node": ">=8" } }, + "node_modules/@istanbuljs/nyc-config-typescript": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/nyc-config-typescript/-/nyc-config-typescript-1.0.2.tgz", + "integrity": "sha512-iKGIyMoyJuFnJRSVTZ78POIRvNnwZaWIf8vG4ZS3rQq58MMDrqEX2nnzx0R28V2X8JvmKYiqY9FP2hlJsm8A0w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "nyc": ">=15" + } + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -797,113 +1231,559 @@ "node": ">= 8.0.0" } }, - "node_modules/@rollup/pluginutils/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@shikijs/core": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.14.1.tgz", + "integrity": "sha512-KyHIIpKNaT20FtFPFjCQB5WVSTpLR/n+jQXhWHWVUMm9MaOaG9BGOG0MSyt7yA4+Lm+4c9rTc03tt3nYzeYSfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.4" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.3.1.tgz", + "integrity": "sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", + "dev": true + }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.6.4.tgz", + "integrity": "sha512-euUGnjzH8EOqEYTGk9dB2OBINp0FX1nuO7/k4fO82zNRBIKZgJoDwTLM4Ce+Om6W1Qmh1PrZjCr4jh4tMEXGPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@stylistic/eslint-plugin-js": "2.6.4", + "@stylistic/eslint-plugin-jsx": "2.6.4", + "@stylistic/eslint-plugin-plus": "2.6.4", + "@stylistic/eslint-plugin-ts": "2.6.4", + "@types/eslint": "^9.6.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.6.4.tgz", + "integrity": "sha512-kx1hS3xTvzxZLdr/DCU/dLBE++vcP97sHeEFX2QXhk1Ipa4K1rzPOLw1HCbf4mU3s+7kHP5eYpDe+QteEOFLug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "^9.6.0", + "acorn": "^8.12.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.6.4.tgz", + "integrity": "sha512-bIvVhdtjmyu3S10V7QRIuawtCZSq9gRmzAX23ucjCOdSFzEwlq+di0IM0riBAvvQerrJL4SM6G3xgyPs8BSXIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@stylistic/eslint-plugin-js": "^2.6.4", + "@types/eslint": "^9.6.0", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@stylistic/eslint-plugin-plus": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.6.4.tgz", + "integrity": "sha512-EuRvtxhf7Hv8OoMIePulP/6rBJIgPTu1l5GAm1780WcF1Cl8bOZXIn84Pdac5pNv6lVlzCOFm8MD3VE+2YROuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "^9.6.0" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@stylistic/eslint-plugin-ts": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.6.4.tgz", + "integrity": "sha512-yxL8Hj6WkObw1jfiLpBzKy5yfxY6vwlwO4miq34ySErUjUecPV5jxfVbOe4q1QDPKemQGPq93v7sAQS5PzM8lA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@stylistic/eslint-plugin-js": "2.6.4", + "@types/eslint": "^9.6.0", + "@typescript-eslint/utils": "^8.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "dev": true + }, + "node_modules/@types/braces": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.4.tgz", + "integrity": "sha512-0WR3b8eaISjEW7RpZnclONaLFDf7buaowRHdqLp4vLj54AsSAYWfh3DRbfiYJY9XDxMgx1B4sE1Afw2PGpuHOA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/clone": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/clone/-/clone-2.1.4.tgz", + "integrity": "sha512-NKRWaEGaVGVLnGLB2GazvDaZnyweW9FJLLFL5LhywGJB3aqGMT9R/EUoJoSRP4nzofYnZysuDmrEJtJdAqUOtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true + }, + "node_modules/@types/micromatch": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.9.tgz", + "integrity": "sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/braces": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.16.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.2.tgz", + "integrity": "sha512-91s/n4qUPV/wg8eE9KHYW1kouTfDk2FPGjXbBMfRWP/2vg1rCXNQL1OCabwGs0XSdukuK+MwCDXE30QpSeMUhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "node_modules/@types/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sinon": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz", + "integrity": "sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.3.0.tgz", + "integrity": "sha512-FLAIn63G5KH+adZosDYiutqkOkYEx0nvcwNNfJAf+c7Ae/H35qWwTYvPZUKFj5AS+WfHG/WJJfWnDnyNUlp8UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/type-utils": "8.3.0", + "@typescript-eslint/utils": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.3.0.tgz", + "integrity": "sha512-h53RhVyLu6AtpUzVCYLPhZGL5jzTD9fZL+SYf/+hYOx2bDkyQXztXSc4tbvKYHzfMXExMLiL9CWqJmVz6+78IQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/typescript-estree": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz", + "integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.3.0.tgz", + "integrity": "sha512-wrV6qh//nLbfXZQoj32EXKmwHf4b7L+xXLrP3FZ0GOUU72gSvLjeWUl5J5Ue5IwRxIV1TfF73j/eaBapxx99Lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.3.0", + "@typescript-eslint/utils": "8.3.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz", + "integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8.6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@sindresorhus/merge-streams": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", - "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz", + "integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { - "type-detect": "4.0.8" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.3.1.tgz", - "integrity": "sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.1" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "node_modules/@typescript-eslint/utils": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz", + "integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==", "dev": true, + "license": "MIT", "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/typescript-estree": "8.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz", + "integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==", "dev": true, + "license": "MIT", "dependencies": { - "type-detect": "4.0.8" + "@typescript-eslint/types": "8.3.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", - "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", - "dev": true - }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", - "dev": true - }, - "node_modules/@types/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", - "dev": true - }, - "node_modules/@types/markdown-it": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", - "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "dependencies": { - "@types/linkify-it": "^5", - "@types/mdurl": "^2" + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@types/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "dev": true - }, "node_modules/@ui5/logger": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@ui5/logger/-/logger-4.0.1.tgz", @@ -2521,6 +3401,46 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, + "node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } + }, "node_modules/escalade": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", @@ -2600,18 +3520,6 @@ } } }, - "node_modules/eslint-config-google": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", - "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "eslint": ">=5.16.0" - } - }, "node_modules/eslint-plugin-ava": { "version": "15.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-ava/-/eslint-plugin-ava-15.0.1.tgz", @@ -3456,6 +4364,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-tsconfig": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz", + "integrity": "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -3599,6 +4520,13 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -4436,6 +5364,13 @@ "yallist": "^3.0.2" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true, + "license": "MIT" + }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -5816,6 +6751,16 @@ "node": ">=8" } }, + "node_modules/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, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -6027,6 +6972,17 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.14.1.tgz", + "integrity": "sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "1.14.1", + "@types/hast": "^3.0.4" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -6705,12 +7661,45 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/tslib": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", "dev": true }, + "node_modules/tsx": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.0.tgz", + "integrity": "sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6750,6 +7739,123 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typedoc": { + "version": "0.26.6", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.26.6.tgz", + "integrity": "sha512-SfEU3SH3wHNaxhFPjaZE2kNl/NFtLNW5c1oHsg7mti7GjmUj1Roq6osBQeMd+F4kL0BoRBBr8gQAuqBlfFu8LA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lunr": "^2.3.9", + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "shiki": "^1.9.1", + "yaml": "^2.4.5" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x" + } + }, + "node_modules/typedoc-plugin-rename-defaults": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.7.1.tgz", + "integrity": "sha512-hgg4mAy5IumgUmPOnVVGmGywjTGtUCmRJ2jRbseqtXdlUuYKj652ODL9joUWFt5uvNu4Dr/pNILc/qsKGHJw+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^8.0.0" + }, + "peerDependencies": { + "typedoc": ">=0.22.x <0.27.x" + } + }, + "node_modules/typedoc-plugin-rename-defaults/node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typedoc/node_modules/yaml": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.3.0.tgz", + "integrity": "sha512-EvWjwWLwwKDIJuBjk2I6UkV8KEQcwZ0VM10nR1rIunRDIP67QJTZAHBXTX0HW/oI1H10YESF8yWie8fRQxjvFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.3.0", + "@typescript-eslint/parser": "8.3.0", + "@typescript-eslint/utils": "8.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", @@ -6762,6 +7868,13 @@ "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", "dev": true }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", From 3edf12cee34a2733b40d5cc242d84506e6db5904 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 29 Aug 2024 11:19:05 +0300 Subject: [PATCH 65/69] fix: TS build issues --- src/Resource.ts | 4 ++-- src/adapters/FileSystem.ts | 4 +++- src/adapters/Memory.ts | 4 ++-- src/fsInterface.ts | 8 +++++--- src/tracing/Trace.ts | 4 ++-- src/tracing/traceSummary.ts | 6 +++--- src/utils/tsUtils.ts | 8 ++++++++ 7 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/Resource.ts b/src/Resource.ts index 9e848eaf..3b61aa93 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -22,7 +22,7 @@ enum ALLOWED_SOURCE_METADATA_KEYS { */ export type Resource_CreateReadableStream = () => stream.Readable; -interface Resource_sourceMetadata { +export interface Resource_sourceMetadata { [ALLOWED_SOURCE_METADATA_KEYS.ADAPTER]?: string; [ALLOWED_SOURCE_METADATA_KEYS.FS_PATH]?: string; [ALLOWED_SOURCE_METADATA_KEYS.CONTENT_MODIFIED]?: boolean; @@ -46,7 +46,7 @@ export interface Resource_Options { }; }; -interface Tree {[x: string]: object | Tree}; +export interface Tree {[x: string]: object | Tree}; export interface LegacyResource { _path: string; diff --git a/src/adapters/FileSystem.ts b/src/adapters/FileSystem.ts index 3e4ba7bd..ae9f83a8 100644 --- a/src/adapters/FileSystem.ts +++ b/src/adapters/FileSystem.ts @@ -13,9 +13,11 @@ import AbstractAdapter from "./AbstractAdapter.js"; import type {Project} from "@ui5/project/specifications/Project"; import Trace from "../tracing/Trace.js"; import {LegacyResource, Resource_Options, ResourceInterface} from "../Resource.js"; +import {isError} from "../utils/tsUtils.js"; const READ_ONLY_MODE = 0o444; const ADAPTER_NAME = "FileSystem"; + /** * File system resource adapter */ @@ -217,7 +219,7 @@ class FileSystem extends AbstractAdapter { return this._createResource(resourceOptions); } catch (err) { - if (err.code === "ENOENT") { // "File or directory does not exist" + if (isError(err) && err.code === "ENOENT") { // "File or directory does not exist" return null; } else { throw err; diff --git a/src/adapters/Memory.ts b/src/adapters/Memory.ts index bfc63e5e..644cac0e 100644 --- a/src/adapters/Memory.ts +++ b/src/adapters/Memory.ts @@ -141,11 +141,11 @@ class Memory extends AbstractAdapter { this._assignProjectToResource(resource); const relPath = this._resolveVirtualPathToBase(resource.getPath(), true); log.silly(`Writing to virtual path ${resource.getPath()}`); - this._virFiles[relPath] = await resource.clone(); + this._virFiles[relPath!] = await resource.clone(); // Add virtual directories for all path segments of the written resource // TODO: Add tests for all this - const pathSegments = relPath.split("/"); + const pathSegments = relPath!.split("/"); pathSegments.pop(); // Remove last segment representing the resource itself pathSegments.forEach((segment, i) => { diff --git a/src/fsInterface.ts b/src/fsInterface.ts index 4c5f6db3..1574b11e 100644 --- a/src/fsInterface.ts +++ b/src/fsInterface.ts @@ -54,7 +54,8 @@ function fsInterface(reader: AbstractReader) { nodir: false, }).then(function (resource) { if (!resource) { - const error = new Error(`ENOENT: no such file or directory, open '${fsPath}'`); + const error: NodeJS.ErrnoException = + new Error(`ENOENT: no such file or directory, open '${fsPath}'`); error.code = "ENOENT"; // "File or directory does not exist" callback(error); return; @@ -64,7 +65,7 @@ function fsInterface(reader: AbstractReader) { let res; if (options?.encoding) { - res = buffer.toString(options.encoding); + res = buffer.toString(options.encoding as BufferEncoding); } else { res = buffer; } @@ -79,7 +80,8 @@ function fsInterface(reader: AbstractReader) { nodir: false, }).then(function (resource) { if (!resource) { - const error = new Error(`ENOENT: no such file or directory, stat '${fsPath}'`); + const error: NodeJS.ErrnoException = + new Error(`ENOENT: no such file or directory, stat '${fsPath}'`); error.code = "ENOENT"; // "File or directory does not exist" callback(error); } else { diff --git a/src/tracing/Trace.ts b/src/tracing/Trace.ts index 8af3b4a8..77f978b3 100644 --- a/src/tracing/Trace.ts +++ b/src/tracing/Trace.ts @@ -14,7 +14,7 @@ class Trace { _startTime!: [number, number]; _globCalls!: number; _pathCalls!: number; - _collections!: CollectionsType; + _collections!: CollectionsType; constructor(name: string) { if (!log.isLevelEnabled("silly")) { @@ -24,7 +24,7 @@ class Trace { this._startTime = process.hrtime(); this._globCalls = 0; this._pathCalls = 0; - this._collections = Object.create(null) as CollectionsType; + this._collections = Object.create(null) as CollectionsType; summaryTrace.traceStarted(); } diff --git a/src/tracing/traceSummary.ts b/src/tracing/traceSummary.ts index 8bf03a32..2e23755c 100644 --- a/src/tracing/traceSummary.ts +++ b/src/tracing/traceSummary.ts @@ -6,13 +6,13 @@ let timeoutId: NodeJS.Timeout; let active = false; let tracesRunning = 0; -export type CollectionsType = T & Record; +export type CollectionsType = Record>; let traceData: null | { startTime: [number, number]; pathCalls: number; globCalls: number; - collections: CollectionsType; + collections: CollectionsType; traceCalls: number; timeDiff?: [number, number]; }; @@ -147,7 +147,7 @@ function globCall() { * @param name TraceData collection name */ function collection(name: string) { - if (!active) { + if (!active || !traceData) { return; } const collection = traceData.collections[name]; diff --git a/src/utils/tsUtils.ts b/src/utils/tsUtils.ts index ba49eef5..a6c89b2d 100644 --- a/src/utils/tsUtils.ts +++ b/src/utils/tsUtils.ts @@ -17,3 +17,11 @@ export function isMigratedResource(resource: unknown): resource is Resource | Re // introduced with v3 therefore take it as the indicator return !!resource && typeof resource === "object" && ("hasProject" in resource); } + +/** + * + * @param error Error to test + */ +export function isError(error: unknown): error is NodeJS.ErrnoException { + return error instanceof Error; +} From 00d11d4f125e0a8f621694c09a192588f13c4801 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 29 Aug 2024 11:22:50 +0300 Subject: [PATCH 66/69] fix: ESLint findings --- src/AbstractReader.ts | 2 +- src/AbstractReaderWriter.ts | 2 +- src/DuplexCollection.ts | 6 +++--- src/ReaderCollection.ts | 4 ++-- src/ReaderCollectionPrioritized.ts | 4 ++-- src/ResourceFacade.ts | 8 ++++---- src/ResourceTagCollection.ts | 2 +- src/WriterCollection.ts | 4 ++-- src/adapters/AbstractAdapter.ts | 4 ++-- src/adapters/FileSystem.ts | 6 +++--- src/adapters/Memory.ts | 6 +++--- src/fsInterface.ts | 4 ++-- src/readers/Filter.ts | 4 ++-- src/readers/Link.ts | 2 +- src/resourceFactory.ts | 12 ++++++------ src/tracing/Trace.ts | 2 +- src/utils/tsUtils.ts | 3 ++- 17 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/AbstractReader.ts b/src/AbstractReader.ts index a3996ac7..a508283a 100644 --- a/src/AbstractReader.ts +++ b/src/AbstractReader.ts @@ -1,6 +1,6 @@ import randomInt from "random-int"; import Trace from "./tracing/Trace.js"; -import {ResourceInterface} from "./Resource.js"; +import {type ResourceInterface} from "./Resource.js"; /** * Abstract resource locator implementing the general API for reading resources diff --git a/src/AbstractReaderWriter.ts b/src/AbstractReaderWriter.ts index fb7665e0..8092b1ec 100644 --- a/src/AbstractReaderWriter.ts +++ b/src/AbstractReaderWriter.ts @@ -1,5 +1,5 @@ import AbstractReader from "./AbstractReader.js"; -import {ResourceInterface} from "./Resource.js"; +import {type ResourceInterface} from "./Resource.js"; /** * Abstract resource locator implementing the general API for reading and writing resources diff --git a/src/DuplexCollection.ts b/src/DuplexCollection.ts index b1363bfc..c29ff93f 100644 --- a/src/DuplexCollection.ts +++ b/src/DuplexCollection.ts @@ -1,8 +1,8 @@ -import AbstractReader from "./AbstractReader.js"; +import type AbstractReader from "./AbstractReader.js"; import AbstractReaderWriter from "./AbstractReaderWriter.js"; import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; -import {ResourceInterface} from "./Resource.js"; -import Trace from "./tracing/Trace.js"; +import {type ResourceInterface} from "./Resource.js"; +import type Trace from "./tracing/Trace.js"; /** * Wrapper to keep readers and writers together diff --git a/src/ReaderCollection.ts b/src/ReaderCollection.ts index 100fe7f3..1de635d6 100644 --- a/src/ReaderCollection.ts +++ b/src/ReaderCollection.ts @@ -1,6 +1,6 @@ import AbstractReader from "./AbstractReader.js"; -import {ResourceInterface} from "./Resource.js"; -import Trace from "./tracing/Trace.js"; +import {type ResourceInterface} from "./Resource.js"; +import type Trace from "./tracing/Trace.js"; /** * Resource Locator ReaderCollection diff --git a/src/ReaderCollectionPrioritized.ts b/src/ReaderCollectionPrioritized.ts index e185e325..4ad4aba6 100644 --- a/src/ReaderCollectionPrioritized.ts +++ b/src/ReaderCollectionPrioritized.ts @@ -1,6 +1,6 @@ import AbstractReader from "./AbstractReader.js"; -import {ResourceInterface} from "./Resource.js"; -import Trace from "./tracing/Trace.js"; +import {type ResourceInterface} from "./Resource.js"; +import type Trace from "./tracing/Trace.js"; /** * Prioritized Resource Locator Collection diff --git a/src/ResourceFacade.ts b/src/ResourceFacade.ts index 403cdfee..7a864e65 100644 --- a/src/ResourceFacade.ts +++ b/src/ResourceFacade.ts @@ -1,8 +1,8 @@ import posixPath from "node:path/posix"; -import {Buffer} from "node:buffer"; -import stream from "node:stream"; -import {Resource_CreateReadableStream, ResourceInterface} from "./Resource.js"; -import {Project} from "@ui5/project/specifications/Project"; +import {type Buffer} from "node:buffer"; +import type stream from "node:stream"; +import {type Resource_CreateReadableStream, type ResourceInterface} from "./Resource.js"; +import {type Project} from "@ui5/project/specifications/Project"; /** * A {@link @ui5/fs/Resource Resource} with a different path than it's original diff --git a/src/ResourceTagCollection.ts b/src/ResourceTagCollection.ts index f9be3eb1..992bc3a9 100644 --- a/src/ResourceTagCollection.ts +++ b/src/ResourceTagCollection.ts @@ -1,6 +1,6 @@ const tagNamespaceRegExp = /^[a-z][a-z0-9]+$/; // part before the colon const tagNameRegExp = /^[A-Z][A-Za-z0-9]+$/; // part after the colon -import {ResourceInterface} from "./Resource.js"; +import {type ResourceInterface} from "./Resource.js"; import ResourceFacade from "./ResourceFacade.js"; interface PathTagsInterface { diff --git a/src/WriterCollection.ts b/src/WriterCollection.ts index ca506369..e6b62369 100644 --- a/src/WriterCollection.ts +++ b/src/WriterCollection.ts @@ -1,8 +1,8 @@ import AbstractReaderWriter from "./AbstractReaderWriter.js"; import ReaderCollection from "./ReaderCollection.js"; import escapeStringRegExp from "escape-string-regexp"; -import Trace from "./tracing/Trace.js"; -import {ResourceInterface} from "./Resource.js"; +import type Trace from "./tracing/Trace.js"; +import {type ResourceInterface} from "./Resource.js"; /** * Resource Locator WriterCollection diff --git a/src/adapters/AbstractAdapter.ts b/src/adapters/AbstractAdapter.ts index 1107ca26..36c89023 100644 --- a/src/adapters/AbstractAdapter.ts +++ b/src/adapters/AbstractAdapter.ts @@ -4,9 +4,9 @@ const log = getLogger("resources:adapters:AbstractAdapter"); import {minimatch} from "minimatch"; import micromatch from "micromatch"; import AbstractReaderWriter from "../AbstractReaderWriter.js"; -import Resource, {Resource_Options, LegacyResource, ResourceInterface} from "../Resource.js"; +import Resource, {type Resource_Options, type LegacyResource, type ResourceInterface} from "../Resource.js"; import type {Project} from "@ui5/project/specifications/Project"; -import Trace from "../tracing/Trace.js"; +import type Trace from "../tracing/Trace.js"; import {isMigratedResource} from "../utils/tsUtils.js"; /** diff --git a/src/adapters/FileSystem.ts b/src/adapters/FileSystem.ts index ae9f83a8..eb3f7919 100644 --- a/src/adapters/FileSystem.ts +++ b/src/adapters/FileSystem.ts @@ -7,12 +7,12 @@ const copyFile = promisify(fs.copyFile); const chmod = promisify(fs.chmod); const mkdir = promisify(fs.mkdir); const stat = promisify(fs.stat); -import {globby, GlobbyFilterFunction, isGitIgnored} from "globby"; +import {globby, type GlobbyFilterFunction, isGitIgnored} from "globby"; import {PassThrough} from "node:stream"; import AbstractAdapter from "./AbstractAdapter.js"; import type {Project} from "@ui5/project/specifications/Project"; -import Trace from "../tracing/Trace.js"; -import {LegacyResource, Resource_Options, ResourceInterface} from "../Resource.js"; +import type Trace from "../tracing/Trace.js"; +import {type LegacyResource, type Resource_Options, type ResourceInterface} from "../Resource.js"; import {isError} from "../utils/tsUtils.js"; const READ_ONLY_MODE = 0o444; diff --git a/src/adapters/Memory.ts b/src/adapters/Memory.ts index 644cac0e..af6d71dc 100644 --- a/src/adapters/Memory.ts +++ b/src/adapters/Memory.ts @@ -2,9 +2,9 @@ import {getLogger} from "@ui5/logger"; const log = getLogger("resources:adapters:Memory"); import micromatch from "micromatch"; import AbstractAdapter from "./AbstractAdapter.js"; -import {Project} from "@ui5/project/specifications/Project"; -import {LegacyResource, ResourceInterface} from "../Resource.js"; -import Trace from "../tracing/Trace.js"; +import {type Project} from "@ui5/project/specifications/Project"; +import {type LegacyResource, type ResourceInterface} from "../Resource.js"; +import type Trace from "../tracing/Trace.js"; const ADAPTER_NAME = "Memory"; diff --git a/src/fsInterface.ts b/src/fsInterface.ts index 1574b11e..bdaece5b 100644 --- a/src/fsInterface.ts +++ b/src/fsInterface.ts @@ -1,6 +1,6 @@ -import AbstractReader from "./AbstractReader.js"; +import type AbstractReader from "./AbstractReader.js"; import type * as fs from "node:fs"; -import {Buffer} from "node:buffer"; +import {type Buffer} from "node:buffer"; /** * diff --git a/src/readers/Filter.ts b/src/readers/Filter.ts index 482dc757..0e0b63d2 100644 --- a/src/readers/Filter.ts +++ b/src/readers/Filter.ts @@ -1,6 +1,6 @@ import AbstractReader from "../AbstractReader.js"; -import {ResourceInterface} from "../Resource.js"; -import Trace from "../tracing/Trace.js"; +import {type ResourceInterface} from "../Resource.js"; +import type Trace from "../tracing/Trace.js"; /** * Filter callback diff --git a/src/readers/Link.ts b/src/readers/Link.ts index 07d7acd8..01e9d44c 100644 --- a/src/readers/Link.ts +++ b/src/readers/Link.ts @@ -3,7 +3,7 @@ import ResourceFacade from "../ResourceFacade.js"; import {prefixGlobPattern} from "../resourceFactory.js"; import {getLogger} from "@ui5/logger"; const log = getLogger("resources:readers:Link"); -import Trace from "../tracing/Trace.js"; +import type Trace from "../tracing/Trace.js"; export interface Link_Args { reader: AbstractReader; diff --git a/src/resourceFactory.ts b/src/resourceFactory.ts index ddd69d23..99da6188 100644 --- a/src/resourceFactory.ts +++ b/src/resourceFactory.ts @@ -5,14 +5,14 @@ import FsAdapter from "./adapters/FileSystem.js"; import MemAdapter from "./adapters/Memory.js"; import ReaderCollection from "./ReaderCollection.js"; import ReaderCollectionPrioritized from "./ReaderCollectionPrioritized.js"; -import Resource, {Resource_Options, ResourceInterface} from "./Resource.js"; +import Resource, {type Resource_Options, type ResourceInterface} from "./Resource.js"; import WriterCollection from "./WriterCollection.js"; -import Filter, {Filter_Params} from "./readers/Filter.js"; -import Link, {Link_Args} from "./readers/Link.js"; +import Filter, {type Filter_Params} from "./readers/Filter.js"; +import Link, {type Link_Args} from "./readers/Link.js"; import {getLogger} from "@ui5/logger"; -import {Project} from "@ui5/project/specifications/Project"; -import AbstractReader from "./AbstractReader.js"; -import AbstractReaderWriter from "./AbstractReaderWriter.js"; +import {type Project} from "@ui5/project/specifications/Project"; +import type AbstractReader from "./AbstractReader.js"; +import type AbstractReaderWriter from "./AbstractReaderWriter.js"; const log = getLogger("resources:resourceFactory"); /** diff --git a/src/tracing/Trace.ts b/src/tracing/Trace.ts index 77f978b3..756ff0b0 100644 --- a/src/tracing/Trace.ts +++ b/src/tracing/Trace.ts @@ -3,7 +3,7 @@ const log = getLogger("resources:tracing:Trace"); const logGlobs = getLogger("resources:tracing:Trace:globs"); const logPaths = getLogger("resources:tracing:Trace:paths"); import prettyHrtime from "pretty-hrtime"; -import summaryTrace, {CollectionsType} from "./traceSummary.js"; +import summaryTrace, {type CollectionsType} from "./traceSummary.js"; /** * Trace diff --git a/src/utils/tsUtils.ts b/src/utils/tsUtils.ts index a6c89b2d..1a08f40b 100644 --- a/src/utils/tsUtils.ts +++ b/src/utils/tsUtils.ts @@ -1,4 +1,5 @@ -import Resource, {ResourceInterface} from "../Resource.js"; +import {type ResourceInterface} from "../Resource.js"; +import type Resource from "../Resource.js"; /** * From aedd08fdfa008d3a99adccfcb363bbda2fc03fdb Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 29 Aug 2024 11:33:44 +0300 Subject: [PATCH 67/69] fix: Match return types --- src/ReaderCollection.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/ReaderCollection.ts b/src/ReaderCollection.ts index 1de635d6..1354f813 100644 --- a/src/ReaderCollection.ts +++ b/src/ReaderCollection.ts @@ -54,7 +54,6 @@ class ReaderCollection extends AbstractReader { */ _byPath(virPath: string, options: {nodir: boolean}, trace: Trace) { const resourceLocatorCount = this._readers.length; - let resolveCount = 0; if (resourceLocatorCount === 0) { // Short-circuit if there are no readers (Promise.race does not settle for empty arrays) @@ -65,16 +64,13 @@ class ReaderCollection extends AbstractReader { // Using Promise.race to deliver files that can be found as fast as possible return Promise.race(this._readers.map((resourceLocator) => { return resourceLocator._byPath(virPath, options, trace).then((resource) => { - return new Promise((resolve) => { - trace.collection(this._name!); - resolveCount++; - if (resource) { - resource.pushCollection(this._name!); - resolve(resource); - } else if (resolveCount === resourceLocatorCount) { - resolve(null); - } - }); + trace.collection(this._name!); + if (resource) { + resource.pushCollection(this._name!); + return resource; + } else { + return null; + } }); })); } From 42cdf090b3d681bfbdbf2fb50a555404ba8d70cc Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 29 Aug 2024 11:37:06 +0300 Subject: [PATCH 68/69] refactor: Lower thresholds for coverage The migration to TS required to use more rows, so now the same old not covered code would take more space/rows and lowers the coverage --- .nycrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nycrc.json b/.nycrc.json index 1ea00929..195a297e 100644 --- a/.nycrc.json +++ b/.nycrc.json @@ -4,7 +4,7 @@ "include": ["src/**"], "check-coverage": true, "statements": 90, - "branches": 90, + "branches": 85, "functions": 90, "lines": 90, "watermarks": { From 3da822dab11bdd6571391b75e8e7884182154a7b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 29 Aug 2024 11:42:59 +0300 Subject: [PATCH 69/69] fix: Remove redundant dependencies & fix depcheck --- package.json | 5 +---- test/lib/Resource.ts | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 629f41a4..4b643463 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "version": "git-chglog --sort semver --next-tag v$npm_package_version -o CHANGELOG.md v4.0.0.. && git add CHANGELOG.md", "prepublishOnly": "git push --follow-tags", "release-note": "git-chglog --sort semver -c .chglog/release-config.yml v$npm_package_version", - "depcheck": "depcheck --ignores @ui5/fs,docdash,@istanbuljs/esm-loader-hook" + "depcheck": "depcheck --ignores @ui5/fs,@ui5/project,docdash,@istanbuljs/esm-loader-hook,tsx,typedoc-plugin-rename-defaults" }, "files": [ "CHANGELOG.md", @@ -134,7 +134,6 @@ "@types/pretty-hrtime": "^1.0.3", "@types/sinon": "^17.0.3", "ava": "^6.1.3", - "chokidar-cli": "^3.0.0", "cross-env": "^7.0.3", "depcheck": "^1.4.7", "docdash": "^2.0.2", @@ -142,8 +141,6 @@ "eslint-plugin-ava": "^15.0.1", "eslint-plugin-jsdoc": "^50.2.2", "esmock": "^2.6.7", - "globals": "^15.9.0", - "jsdoc": "^4.0.3", "nyc": "^17.0.0", "open-cli": "^8.0.0", "rimraf": "^6.0.1", diff --git a/test/lib/Resource.ts b/test/lib/Resource.ts index 2c09da42..7c560bc7 100644 --- a/test/lib/Resource.ts +++ b/test/lib/Resource.ts @@ -3,7 +3,7 @@ import {Stream, Transform, type Readable} from "node:stream"; import {promises as fs, createReadStream} from "node:fs"; import path from "node:path"; import Resource from "../../src/Resource.js"; -import {type Project} from "@ui5/project/specifications/Project"; +import type {Project} from "@ui5/project/specifications/Project"; function createBasicResource() { const fsPath = path.join("test", "fixtures", "application.a", "webapp", "index.html");