componentsjs 5.5.1 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -85,7 +85,7 @@ export class MyClass {
85
85
  ```json
86
86
  {
87
87
  "@context": [
88
- "https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^5.0.0/components/context.jsonld",
88
+ "https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^6.0.0/components/context.jsonld",
89
89
  "https://linkedsoftwaredependencies.org/bundles/npm/my-package/^2.0.0/components/context.jsonld"
90
90
  ],
91
91
  "@id": "urn:my-package:myInstance",
@@ -139,7 +139,7 @@ export class MyClass {
139
139
  ```json
140
140
  {
141
141
  "@context": [
142
- "https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^5.0.0/components/context.jsonld",
142
+ "https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^6.0.0/components/context.jsonld",
143
143
  { "ex": "http://example.org/" }
144
144
  ],
145
145
  "@id": "ex:MyPackage",
@@ -171,7 +171,7 @@ The constructor of `MyClass` takes a single `name` argument.
171
171
  ```json
172
172
  {
173
173
  "@context": [
174
- "https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^5.0.0/components/context.jsonld",
174
+ "https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^6.0.0/components/context.jsonld",
175
175
  {
176
176
  "ex": "http://example.org/",
177
177
  "name": "ex:MyPackage/MyClass#name"
@@ -18,6 +18,7 @@ export declare class ComponentRegistry {
18
18
  private readonly logger;
19
19
  private readonly componentResources;
20
20
  private readonly skipContextValidation;
21
+ private readonly remoteContextLookups;
21
22
  constructor(options: IComponentLoaderRegistryOptions);
22
23
  /**
23
24
  * Register all modules and their components that are available in the {@link IModuleState}.
@@ -65,4 +66,5 @@ export interface IComponentLoaderRegistryOptions {
65
66
  logger: Logger;
66
67
  componentResources: Record<string, Resource>;
67
68
  skipContextValidation: boolean;
69
+ remoteContextLookups: boolean;
68
70
  }
@@ -17,6 +17,7 @@ class ComponentRegistry {
17
17
  this.logger = options.logger;
18
18
  this.componentResources = options.componentResources;
19
19
  this.skipContextValidation = options.skipContextValidation;
20
+ this.remoteContextLookups = options.remoteContextLookups;
20
21
  }
21
22
  /**
22
23
  * Register all modules and their components that are available in the {@link IModuleState}.
@@ -25,6 +26,7 @@ class ComponentRegistry {
25
26
  */
26
27
  async registerAvailableModules() {
27
28
  await Promise.all(Object.values(this.moduleState.componentModules)
29
+ .flatMap(Object.values)
28
30
  .map((moduleResourceUrl) => this.registerModule(moduleResourceUrl)));
29
31
  }
30
32
  /**
@@ -39,6 +41,7 @@ class ComponentRegistry {
39
41
  importPaths: this.moduleState.importPaths,
40
42
  logger: this.logger,
41
43
  skipContextValidation: this.skipContextValidation,
44
+ remoteContextLookups: this.remoteContextLookups,
42
45
  }));
43
46
  }
44
47
  /**
@@ -19,6 +19,7 @@ export declare class ComponentsManagerBuilder<Instance = any> {
19
19
  private readonly moduleState?;
20
20
  private readonly skipContextValidation;
21
21
  private readonly typeChecking;
22
+ private readonly remoteContextLookups;
22
23
  constructor(options: IComponentsManagerBuilderOptions<Instance>);
23
24
  static createLogger(logLevel?: LogLevel): Logger;
24
25
  static createObjectLoader(): RdfObjectLoader;
@@ -75,4 +76,11 @@ export interface IComponentsManagerBuilderOptions<Instance> {
75
76
  * Defaults to `true`.
76
77
  */
77
78
  typeChecking?: boolean;
79
+ /**
80
+ * If remote context lookups are allowed.
81
+ * If not allowed, an error is thrown if a remote lookup occurs.
82
+ * If allowed, only a warning is emitted.
83
+ * Defaults to `false`.
84
+ */
85
+ remoteContextLookups?: boolean;
78
86
  }
@@ -34,6 +34,9 @@ class ComponentsManagerBuilder {
34
34
  this.typeChecking = options.typeChecking === undefined ?
35
35
  true :
36
36
  Boolean(options.typeChecking);
37
+ this.remoteContextLookups = options.remoteContextLookups === undefined ?
38
+ false :
39
+ Boolean(options.typeChecking);
37
40
  }
38
41
  static createLogger(logLevel = 'warn') {
39
42
  return (0, winston_1.createLogger)({
@@ -76,6 +79,7 @@ class ComponentsManagerBuilder {
76
79
  logger: this.logger,
77
80
  componentResources,
78
81
  skipContextValidation: this.skipContextValidation,
82
+ remoteContextLookups: this.remoteContextLookups,
79
83
  });
80
84
  await this.componentLoader(componentRegistry);
81
85
  const componentFinalizer = new ComponentRegistryFinalizer_1.ComponentRegistryFinalizer({
@@ -91,6 +95,7 @@ class ComponentsManagerBuilder {
91
95
  objectLoader,
92
96
  logger: this.logger,
93
97
  skipContextValidation: this.skipContextValidation,
98
+ remoteContextLookups: this.remoteContextLookups,
94
99
  });
95
100
  await this.configLoader(configRegistry);
96
101
  this.logger.info(`Loaded configs`);
@@ -12,6 +12,7 @@ export declare class ConfigRegistry {
12
12
  private readonly objectLoader;
13
13
  private readonly logger;
14
14
  private readonly skipContextValidation;
15
+ private readonly remoteContextLookups;
15
16
  constructor(options: IConfigLoaderRegistryOptions);
16
17
  /**
17
18
  * Register a config based on a config URL or local file path.
@@ -41,4 +42,5 @@ export interface IConfigLoaderRegistryOptions {
41
42
  objectLoader: RdfObjectLoader;
42
43
  logger: Logger;
43
44
  skipContextValidation: boolean;
45
+ remoteContextLookups: boolean;
44
46
  }
@@ -12,6 +12,7 @@ class ConfigRegistry {
12
12
  this.objectLoader = options.objectLoader;
13
13
  this.logger = options.logger;
14
14
  this.skipContextValidation = options.skipContextValidation;
15
+ this.remoteContextLookups = options.remoteContextLookups;
15
16
  }
16
17
  /**
17
18
  * Register a config based on a config URL or local file path.
@@ -26,6 +27,7 @@ class ConfigRegistry {
26
27
  ignoreImports: false,
27
28
  logger: this.logger,
28
29
  skipContextValidation: this.skipContextValidation,
30
+ remoteContextLookups: this.remoteContextLookups,
29
31
  }));
30
32
  }
31
33
  /**
@@ -51,13 +51,13 @@ export declare class ModuleStateBuilder {
51
51
  * @returns If the package has been preprocessed.
52
52
  */
53
53
  static preprocessPackageJson(packagePath: string, packageJson: Record<string, any>): Promise<boolean>;
54
- protected shouldOverrideVersion(version: string, key: string, componentVersions: Record<string, string>, warningSuffix: string): boolean;
54
+ protected shouldOverrideVersion(version: string, key: string, componentVersion: string | undefined, warningSuffix?: () => string): boolean;
55
55
  /**
56
56
  * Get all Components.js modules from the given package.json files.
57
57
  * @param packageJsons A hash of Node module path to package.json contents.
58
58
  * @return A hash of module id (`lsd:module`) to absolute component paths (`lsd:components`).
59
59
  */
60
- buildComponentModules(packageJsons: Record<string, any>): Promise<Record<string, string>>;
60
+ buildComponentModules(packageJsons: Record<string, any>): Promise<Record<string, Record<number, string>>>;
61
61
  /**
62
62
  * Get all Components.js contexts from the given package.json files.
63
63
  * @param packageJsons A hash of Node module path to package.json contents.
@@ -96,10 +96,10 @@ export interface IModuleState {
96
96
  packageJsons: Record<string, any>;
97
97
  /**
98
98
  * All Components.js modules.
99
- * This hash maps module IRIs (`lsd:module`)
99
+ * This hash maps module IRIs (`lsd:module`) to major version
100
100
  * to absolute component paths (`lsd:components`).
101
101
  */
102
- componentModules: Record<string, string>;
102
+ componentModules: Record<string, Record<number, string>>;
103
103
  /**
104
104
  * All Components.js contexts.
105
105
  * This hash maps context IRIs (key of `lsd:contexts`)
@@ -205,12 +205,12 @@ class ModuleStateBuilder {
205
205
  }
206
206
  return false;
207
207
  }
208
- shouldOverrideVersion(version, key, componentVersions, warningSuffix) {
209
- if (key in componentVersions) {
210
- if (semverMajor(version) !== semverMajor(componentVersions[key])) {
211
- this.warn(`Detected multiple incompatible occurrences of '${key}'${warningSuffix}`);
208
+ shouldOverrideVersion(version, key, componentVersion, warningSuffix) {
209
+ if (componentVersion !== undefined) {
210
+ if (warningSuffix && semverMajor(version) !== semverMajor(componentVersion)) {
211
+ this.warn(`Detected multiple incompatible occurrences of '${key}'${warningSuffix()}`);
212
212
  }
213
- if (semverGt(version, componentVersions[key])) {
213
+ if (semverGt(version, componentVersion)) {
214
214
  return true;
215
215
  }
216
216
  return false;
@@ -230,10 +230,15 @@ class ModuleStateBuilder {
230
230
  const relativePath = pckg['lsd:components'];
231
231
  const version = pckg.version;
232
232
  if (version && currentModuleUri && relativePath && semverValid(version)) {
233
+ if (!componentModules[currentModuleUri]) {
234
+ componentModules[currentModuleUri] = {};
235
+ componentVersions[currentModuleUri] = {};
236
+ }
237
+ const versionMajor = semverMajor(version);
233
238
  const absolutePath = Path.posix.join(modulePath, relativePath);
234
- if (this.shouldOverrideVersion(version, currentModuleUri, componentVersions, `, in '${componentModules[currentModuleUri]}'@${componentVersions[currentModuleUri]} and '${absolutePath}'@${version}`)) {
235
- componentModules[currentModuleUri] = absolutePath;
236
- componentVersions[currentModuleUri] = version;
239
+ if (this.shouldOverrideVersion(version, currentModuleUri, componentVersions[currentModuleUri][versionMajor])) {
240
+ componentModules[currentModuleUri][versionMajor] = absolutePath;
241
+ componentVersions[currentModuleUri][versionMajor] = version;
237
242
  }
238
243
  }
239
244
  }
@@ -254,7 +259,7 @@ class ModuleStateBuilder {
254
259
  for (const [key, value] of Object.entries(contexts)) {
255
260
  const filePath = Path.posix.join(modulePath, value);
256
261
  const fileContents = JSON.parse(await fs.readFile(filePath, 'utf8'));
257
- if (this.shouldOverrideVersion(version, key, componentVersions, ` for version ${componentVersions[key]} and '${filePath}'@${version}`)) {
262
+ if (this.shouldOverrideVersion(version, key, componentVersions[key], () => ` for version ${componentVersions[key]} and '${filePath}'@${version}`)) {
258
263
  componentContexts[key] = fileContents;
259
264
  componentVersions[key] = version;
260
265
  }
@@ -277,7 +282,7 @@ class ModuleStateBuilder {
277
282
  if (version && importPaths && semverValid(version)) {
278
283
  for (const [key, value] of Object.entries(importPaths)) {
279
284
  const filePath = Path.posix.join(modulePath, value);
280
- if (this.shouldOverrideVersion(version, key, componentVersions, ` for version ${componentVersions[key]} and '${filePath}'@${version}`)) {
285
+ if (this.shouldOverrideVersion(version, key, componentVersions[key], () => ` for version ${componentVersions[key]} and '${filePath}'@${version}`)) {
281
286
  componentImportPaths[key] = filePath;
282
287
  componentVersions[key] = version;
283
288
  // Crash when the context prefix target does not exist
@@ -396,7 +396,8 @@ class ParameterPropertyHandlerRange {
396
396
  const withTypes = value && value.properties.types.length > 0 ? ` with types "${value.properties.types.map(resource => resource.value)}"` : '';
397
397
  // eslint-disable-next-line @typescript-eslint/no-extra-parens
398
398
  const valueString = value ? (value.list ? `[${value.list.map(subValue => subValue.value).join(', ')}]` : value.value) : 'undefined';
399
- throw new ErrorResourcesContext_1.ErrorResourcesContext(`The value "${valueString}"${withTypes} for parameter "${parameter.value}" is not of required range type "${ParameterPropertyHandlerRange.rangeToDisplayString(parameter.property.range, genericsContext)}"`, Object.assign(Object.assign({ cause: conflict, value: value || 'undefined' }, Object.keys(genericsContext.bindings).length > 0 ?
399
+ const undefinedComponent = value && value.term.termType === 'NamedNode' && value.properties.types.length === 0 ? `. "${valueString}" seems to refer to a component instance that is not defined yet. Did you forget an import?` : '';
400
+ throw new ErrorResourcesContext_1.ErrorResourcesContext(`The value "${valueString}"${withTypes} for parameter "${parameter.value}" is not of required range type "${ParameterPropertyHandlerRange.rangeToDisplayString(parameter.property.range, genericsContext)}"${undefinedComponent}`, Object.assign(Object.assign({ cause: conflict, value: value || 'undefined' }, Object.keys(genericsContext.bindings).length > 0 ?
400
401
  { generics: `[\n ${Object.entries(genericsContext.bindings)
401
402
  .map(([id, subValue]) => `<${id}> => ${ParameterPropertyHandlerRange.rangeToDisplayString(subValue, genericsContext)}`)
402
403
  .join(',\n ')}\n]` } :
@@ -6,12 +6,15 @@ import type { Logger } from 'winston';
6
6
  * and only then does an HTTP(S) lookup for the context.
7
7
  */
8
8
  export declare class PrefetchedDocumentLoader extends FetchDocumentLoader {
9
+ static readonly CJS_MAJOR_VERSION: number;
9
10
  static readonly CONTEXT_URL: string;
11
+ static readonly CONTEXT_PATTERN: RegExp;
10
12
  private static readonly DEFAULT_CONTEXT;
11
13
  private static readonly DEFAULT_CONTEXTS;
12
14
  private readonly contexts;
13
15
  private readonly path?;
14
16
  private readonly logger?;
17
+ private readonly remoteContextLookups?;
15
18
  constructor(options: IPrefetchedDocumentLoaderOptions);
16
19
  load(url: string): Promise<IJsonLdContext>;
17
20
  }
@@ -19,4 +22,5 @@ export interface IPrefetchedDocumentLoaderOptions {
19
22
  contexts: Record<string, any>;
20
23
  logger?: Logger;
21
24
  path?: string;
25
+ remoteContextLookups?: boolean;
22
26
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PrefetchedDocumentLoader = void 0;
4
4
  const jsonld_context_parser_1 = require("jsonld-context-parser");
5
+ const semverMajor = require("semver/functions/major");
5
6
  /**
6
7
  * A document loader that first loads from a precomputed set of contexts,
7
8
  * and only then does an HTTP(S) lookup for the context.
@@ -12,32 +13,36 @@ class PrefetchedDocumentLoader extends jsonld_context_parser_1.FetchDocumentLoad
12
13
  this.contexts = Object.assign(Object.assign({}, options.contexts), PrefetchedDocumentLoader.DEFAULT_CONTEXTS);
13
14
  this.logger = options.logger;
14
15
  this.path = options.path;
16
+ this.remoteContextLookups = options.remoteContextLookups;
15
17
  }
16
18
  async load(url) {
17
- // Warn on deprecated context usage
18
- if (this.logger &&
19
- (url === 'https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^4.0.0/components/context.jsonld' ||
20
- url === 'https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^3.0.0/components/context.jsonld')) {
21
- this.logger.warn(`Detected deprecated context URL '${url}'${this.path ? ` in ${this.path}` : ''}. Prefer using version '^5.0.0' instead.`);
22
- }
23
19
  // Load prefetched contexts
24
20
  if (url in this.contexts) {
25
21
  return this.contexts[url];
26
22
  }
27
23
  // Warn before doing a remote context lookup
24
+ const errorMessage = `Detected remote context lookup for '${url}'${this.path ? ` in ${this.path}` : ''}. This may indicate a missing or invalid dependency, incorrect version number, or an invalid context URL.`;
25
+ if (!this.remoteContextLookups) {
26
+ throw new Error(errorMessage);
27
+ }
28
28
  if (this.logger) {
29
- this.logger.warn(`Detected remote context lookup for '${url}'${this.path ? ` in ${this.path}` : ''}. This may indicate a missing or invalid dependency, incorrect version number, or an invalid context URL.`);
29
+ this.logger.warn(errorMessage);
30
30
  }
31
31
  return super.load(url);
32
32
  }
33
33
  }
34
- PrefetchedDocumentLoader.CONTEXT_URL = 'https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^5.0.0/components/context.jsonld';
34
+ PrefetchedDocumentLoader.CJS_MAJOR_VERSION = semverMajor(require('../../package.json').version);
35
+ PrefetchedDocumentLoader.CONTEXT_URL = `https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^${PrefetchedDocumentLoader.CJS_MAJOR_VERSION}.0.0/components/context.jsonld`;
36
+ PrefetchedDocumentLoader.CONTEXT_PATTERN = /https:\/\/linkedsoftwaredependencies.org\/bundles\/npm\/componentsjs\/\^([0-9]+).0.0\/components\/context.jsonld/u;
35
37
  PrefetchedDocumentLoader.DEFAULT_CONTEXT = require('../../components/context.json');
36
38
  PrefetchedDocumentLoader.DEFAULT_CONTEXTS = {
37
39
  [PrefetchedDocumentLoader.CONTEXT_URL]: PrefetchedDocumentLoader.DEFAULT_CONTEXT,
38
- // TODO: temporarily also set old context versions for backwards-compatible.
39
- 'https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^4.0.0/components/context.jsonld': PrefetchedDocumentLoader.DEFAULT_CONTEXT,
40
- 'https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^3.0.0/components/context.jsonld': PrefetchedDocumentLoader.DEFAULT_CONTEXT,
41
40
  };
41
+ (() => {
42
+ // TODO: temporarily also set old context versions for backwards-compatible.
43
+ for (let i = 3; i < PrefetchedDocumentLoader.CJS_MAJOR_VERSION; i++) {
44
+ PrefetchedDocumentLoader.DEFAULT_CONTEXTS[`https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^${i}.0.0/components/context.jsonld`] = PrefetchedDocumentLoader.DEFAULT_CONTEXT;
45
+ }
46
+ })();
42
47
  exports.PrefetchedDocumentLoader = PrefetchedDocumentLoader;
43
48
  //# sourceMappingURL=PrefetchedDocumentLoader.js.map
@@ -58,4 +58,10 @@ export type RdfParserOptions = ParseOptions & {
58
58
  * If JSON-LD context validation should be skipped.
59
59
  */
60
60
  skipContextValidation?: boolean;
61
+ /**
62
+ * If remote context lookups are allowed.
63
+ * If not allowed, an error is thrown if a remote lookup occurs.
64
+ * If allowed, only a warning is emitted.
65
+ */
66
+ remoteContextLookups?: boolean;
61
67
  };
@@ -45,6 +45,7 @@ class RdfParser {
45
45
  contexts: options.contexts || {},
46
46
  logger: options.logger,
47
47
  path: options.path,
48
+ remoteContextLookups: options.remoteContextLookups,
48
49
  }),
49
50
  // Enable strict parsing of JSON-LD to error on potential user config errors
50
51
  strictValues: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "componentsjs",
3
- "version": "5.5.1",
3
+ "version": "6.0.1",
4
4
  "description": "A semantic dependency injection framework",
5
5
  "lsd:contexts": {
6
6
  "https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^5.0.0/components/context.jsonld": "components/context.jsonld"
@@ -21,7 +21,7 @@
21
21
  "license": "MIT",
22
22
  "packageManager": "yarn@4.0.1",
23
23
  "scripts": {
24
- "test": "yarn test:jest && yarn test:webpack",
24
+ "test": "yarn test:jest",
25
25
  "test:jest": "jest",
26
26
  "test:webpack": "yarn test:webpack:node && yarn test:webpack:web",
27
27
  "test:webpack:node": "webpack -c test/webpack/webpack.config.js && node test/webpack/build/test.min.js",