diff --git a/docs/api.md b/docs/api.md index 8d9cb36fad..f4e97d0c63 100644 --- a/docs/api.md +++ b/docs/api.md @@ -58,6 +58,9 @@
DB API: zcl loading queries

This module provides queries for ZCL loading

+
DB API: session related queries.
+

This module provides notification related queries.

+
DB API: package-based queries.

This module provides queries related to packages.

@@ -788,7 +791,7 @@ NOTE: This function does NOT initialize session packages.

importSessionKeyValues(db, sessionId, keyValuePairs)

Resolves with a promise that imports session key values.

-
jsonDataLoader(db, state, sessionId)
+
jsonDataLoader(db, state, sessionId, packageMatch)

Given a state object, this method returns a promise that resolves with the succesfull writing into the database.

@@ -1009,12 +1012,6 @@ and orchestrates the promise chain.

loadIndividualFile(db, filePath, sessionId)

Load individual custom XML files.

-
bindValidationScript(db, basePackageId)
-

This function creates a validator function with signatuee fn(stringToValidateOn)

-
-
getSchemaAndValidationScript(db, basePackageId)
-

Returns an object with zclSchema and zclValidation elements.

-
qualifyZclFile(db, info, parentPackageId)

Promises to qualify whether zcl file needs to be reloaded. If yes, the it will resolve with {filePath, data, packageId} @@ -1158,9 +1155,6 @@ that will be resolved when all the XML files are done, or rejected if at least o

parseProfilesData(db, ctx)

Parses the profiles xml.

-
parseZclSchema(db)
-

Parses the ZCL Schema

-
parseFeatureFlags(db, packageId, featureFlags)

Inside the zcl.json can be a featureFlags key, which is a general purpose object. It contains keys, that map to objects. @@ -1221,6 +1215,7 @@ This module provides generic DB functions for performing SQL queries. - [JS API: low level database access](#module*JS API* low level database access) - [~dbBeginTransaction(db)](#module*JS API* low level database access..dbBeginTransaction) ⇒ - [~dbCommit(db)](#module*JS API* low level database access..dbCommit) ⇒ + - [~isTransactionActive()](#module*JS API* low level database access..isTransactionActive) ⇒ - [~dbRollback(db)](#module*JS API* low level database access..dbRollback) ⇒ - [~dbRemove(db, query, args)](#module*JS API* low level database access..dbRemove) ⇒ - [~dbUpdate(db, query, args)](#module*JS API* low level database access..dbUpdate) ⇒ @@ -1277,6 +1272,15 @@ Returns a promise to execute a commit. | ----- | --------------- | | db | \* | + + +### JS API: low level database access~isTransactionActive() ⇒ + +Not an async function, simply returns a boolean value whether +there is a currently active transaction. + +**Kind**: inner method of [JS API: low level database access](#module*JS API* low level database access) +**Returns**: true if transaction is active, false if not. ### JS API: low level database access~dbRollback(db) ⇒ @@ -4254,6 +4258,12 @@ Insert all Struct items into the Struct Item Table. | packageIds | \* | | data | \* | + + +## DB API: session related queries. + +This module provides notification related queries. + ## DB API: package-based queries. @@ -5845,11 +5855,12 @@ Query for attributes by side. ## JS API: generator logic - [JS API: generator logic](#module*JS API* generator logic) - - [~loadGenTemplate()](#module*JS API* generator logic..loadGenTemplate) ⇒ + - [~loadGenTemplateFromFile(path)](#module*JS API* generator logic..loadGenTemplateFromFile) ⇒ - [~recordTemplatesPackage(context)](#module*JS API* generator logic..recordTemplatesPackage) ⇒ - [~decodePackageExtensionEntity(entityType, entity)](#module*JS API* generator logic..decodePackageExtensionEntity) ⇒ - [~loadZclExtensions(zclExt)](#module*JS API* generator logic..loadZclExtensions) ⇒ - - [~loadTemplates(db, genTemplatesJson)](#module*JS API* generator logic..loadTemplates) ⇒ + - [~loadTemplates(db, genTemplatesJsonArray)](#module*JS API* generator logic..loadTemplates) + - [~loadSingleTemplate(db, genTemplatesJson)](#module*JS API* generator logic..loadSingleTemplate) ⇒ - [~generateAllTemplates(genResult, genTemplateJsonPkg, generateOnly)](#module*JS API* generator logic..generateAllTemplates) ⇒ - [~generateSingleTemplate(genResult, singleTemplatePkg)](#module*JS API* generator logic..generateSingleTemplate) ⇒ - [~generate(db, packageId)](#module*JS API* generator logic..generate) ⇒ @@ -5884,18 +5895,18 @@ Query for attributes by side. - [~templatePromise(global, promise)](#module*JS API* generator logic..templatePromise) - [~deprecatedHelper(fn, explanation)](#module*JS API* generator logic..deprecatedHelper) ⇒ - + -### JS API: generator logic~loadGenTemplate() ⇒ +### JS API: generator logic~loadGenTemplateFromFile(path) ⇒ Given a path, it will read generation template object into memory. **Kind**: inner method of [JS API: generator logic](#module*JS API* generator logic) -**Returns**: context.templates, context.crc +**Returns**: Object that contains: data, crc, templateData -| Param | Type | -| ------------ | --------------- | -| context.path | \* | +| Param | Type | +| ----- | --------------- | +| path | \* | @@ -5941,17 +5952,31 @@ Returns a promise that will load the zcl extensions. -### JS API: generator logic~loadTemplates(db, genTemplatesJson) ⇒ +### JS API: generator logic~loadTemplates(db, genTemplatesJsonArray) + +Api that loads an array of template JSON files or a single file if +you just pass in one String. + +**Kind**: inner method of [JS API: generator logic](#module*JS API* generator logic) + +| Param | Type | +| --------------------- | --------------- | +| db | \* | +| genTemplatesJsonArray | \* | + + + +### JS API: generator logic~loadSingleTemplate(db, genTemplatesJson) ⇒ Main API async function to load templates from a gen-template.json file. **Kind**: inner method of [JS API: generator logic](#module*JS API* generator logic) **Returns**: the loading context, contains: db, path, crc, packageId and templateData, or error -| Param | Type | Description | -| ---------------- | --------------- | --------------------- | -| db | \* | Database | -| genTemplatesJson | \* | Path to the JSON file | +| Param | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------- | +| db | \* | Database | +| genTemplatesJson | \* | Path to the JSON file or an array of paths to JSON file | @@ -8392,6 +8417,8 @@ This module contains the API for templating. For more detailed instructions, rea - [~as_type_min_value(type, options)](#module*Templating API* static zcl helpers..as_type_min_value) ⇒ - [~as_type_max_value(type, options)](#module*Templating API* static zcl helpers..as_type_max_value) ⇒ - [~structs_with_clusters(options)](#module*Templating API* static zcl helpers..structs_with_clusters) + - [~as_zcl_type_size(type, options)](#module*Templating API* static zcl helpers..as_zcl_type_size) ⇒ + - [~if_compare(leftValue, rightValue, options)](#module*Templating API* static zcl helpers..if_compare) ⇒ Object @@ -9543,6 +9570,41 @@ Returns all structs which have clusters associated with them | ------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | options | \* | Available Options: - groupByStructName: Can group the query results based on struct name for structs which are present in more than one cluster eg Usage: {{#structs_with_clusters groupByStructName=1}}{{/structs_with_clusters}} | + + +### Templating API: static zcl helpers~as_zcl_type_size(type, options) ⇒ + +Returns the size of the zcl type if possible else returns -1 + +**Kind**: inner method of [Templating API: static zcl helpers](#module*Templating API* static zcl helpers) +**Returns**: size of zcl type + +| Param | Type | +| ------- | --------------- | +| type | \* | +| options | \* | + + + +### Templating API: static zcl helpers~if_compare(leftValue, rightValue, options) ⇒ Object + +An if helper for comparisons + +**Kind**: inner method of [Templating API: static zcl helpers](#module*Templating API* static zcl helpers) +**Returns**: Object - Promise of content +example: checking if (4 < 5) +(if_compare 4 5 operator='<') +Content when comparison returns true + +Content when comparison returns false +(/if_compare) + +| Param | Type | +| ---------- | --------------- | +| leftValue | \* | +| rightValue | \* | +| options | \* | + ## Templating API: Overridable functions. @@ -9554,11 +9616,12 @@ This module contains the API for templating. For more detailed instructions, rea ## JS API: generator logic - [JS API: generator logic](#module*JS API* generator logic) - - [~loadGenTemplate()](#module*JS API* generator logic..loadGenTemplate) ⇒ + - [~loadGenTemplateFromFile(path)](#module*JS API* generator logic..loadGenTemplateFromFile) ⇒ - [~recordTemplatesPackage(context)](#module*JS API* generator logic..recordTemplatesPackage) ⇒ - [~decodePackageExtensionEntity(entityType, entity)](#module*JS API* generator logic..decodePackageExtensionEntity) ⇒ - [~loadZclExtensions(zclExt)](#module*JS API* generator logic..loadZclExtensions) ⇒ - - [~loadTemplates(db, genTemplatesJson)](#module*JS API* generator logic..loadTemplates) ⇒ + - [~loadTemplates(db, genTemplatesJsonArray)](#module*JS API* generator logic..loadTemplates) + - [~loadSingleTemplate(db, genTemplatesJson)](#module*JS API* generator logic..loadSingleTemplate) ⇒ - [~generateAllTemplates(genResult, genTemplateJsonPkg, generateOnly)](#module*JS API* generator logic..generateAllTemplates) ⇒ - [~generateSingleTemplate(genResult, singleTemplatePkg)](#module*JS API* generator logic..generateSingleTemplate) ⇒ - [~generate(db, packageId)](#module*JS API* generator logic..generate) ⇒ @@ -9593,18 +9656,18 @@ This module contains the API for templating. For more detailed instructions, rea - [~templatePromise(global, promise)](#module*JS API* generator logic..templatePromise) - [~deprecatedHelper(fn, explanation)](#module*JS API* generator logic..deprecatedHelper) ⇒ - + -### JS API: generator logic~loadGenTemplate() ⇒ +### JS API: generator logic~loadGenTemplateFromFile(path) ⇒ Given a path, it will read generation template object into memory. **Kind**: inner method of [JS API: generator logic](#module*JS API* generator logic) -**Returns**: context.templates, context.crc +**Returns**: Object that contains: data, crc, templateData -| Param | Type | -| ------------ | --------------- | -| context.path | \* | +| Param | Type | +| ----- | --------------- | +| path | \* | @@ -9650,17 +9713,31 @@ Returns a promise that will load the zcl extensions. -### JS API: generator logic~loadTemplates(db, genTemplatesJson) ⇒ +### JS API: generator logic~loadTemplates(db, genTemplatesJsonArray) + +Api that loads an array of template JSON files or a single file if +you just pass in one String. + +**Kind**: inner method of [JS API: generator logic](#module*JS API* generator logic) + +| Param | Type | +| --------------------- | --------------- | +| db | \* | +| genTemplatesJsonArray | \* | + + + +### JS API: generator logic~loadSingleTemplate(db, genTemplatesJson) ⇒ Main API async function to load templates from a gen-template.json file. **Kind**: inner method of [JS API: generator logic](#module*JS API* generator logic) **Returns**: the loading context, contains: db, path, crc, packageId and templateData, or error -| Param | Type | Description | -| ---------------- | --------------- | --------------------- | -| db | \* | Database | -| genTemplatesJson | \* | Path to the JSON file | +| Param | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------- | +| db | \* | Database | +| genTemplatesJson | \* | Path to the JSON file or an array of paths to JSON file | @@ -10122,11 +10199,12 @@ Function wrapper that can be used when a helper is deprecated. ## JS API: generator logic - [JS API: generator logic](#module*JS API* generator logic) - - [~loadGenTemplate()](#module*JS API* generator logic..loadGenTemplate) ⇒ + - [~loadGenTemplateFromFile(path)](#module*JS API* generator logic..loadGenTemplateFromFile) ⇒ - [~recordTemplatesPackage(context)](#module*JS API* generator logic..recordTemplatesPackage) ⇒ - [~decodePackageExtensionEntity(entityType, entity)](#module*JS API* generator logic..decodePackageExtensionEntity) ⇒ - [~loadZclExtensions(zclExt)](#module*JS API* generator logic..loadZclExtensions) ⇒ - - [~loadTemplates(db, genTemplatesJson)](#module*JS API* generator logic..loadTemplates) ⇒ + - [~loadTemplates(db, genTemplatesJsonArray)](#module*JS API* generator logic..loadTemplates) + - [~loadSingleTemplate(db, genTemplatesJson)](#module*JS API* generator logic..loadSingleTemplate) ⇒ - [~generateAllTemplates(genResult, genTemplateJsonPkg, generateOnly)](#module*JS API* generator logic..generateAllTemplates) ⇒ - [~generateSingleTemplate(genResult, singleTemplatePkg)](#module*JS API* generator logic..generateSingleTemplate) ⇒ - [~generate(db, packageId)](#module*JS API* generator logic..generate) ⇒ @@ -10161,18 +10239,18 @@ Function wrapper that can be used when a helper is deprecated. - [~templatePromise(global, promise)](#module*JS API* generator logic..templatePromise) - [~deprecatedHelper(fn, explanation)](#module*JS API* generator logic..deprecatedHelper) ⇒ - + -### JS API: generator logic~loadGenTemplate() ⇒ +### JS API: generator logic~loadGenTemplateFromFile(path) ⇒ Given a path, it will read generation template object into memory. **Kind**: inner method of [JS API: generator logic](#module*JS API* generator logic) -**Returns**: context.templates, context.crc +**Returns**: Object that contains: data, crc, templateData -| Param | Type | -| ------------ | --------------- | -| context.path | \* | +| Param | Type | +| ----- | --------------- | +| path | \* | @@ -10218,17 +10296,31 @@ Returns a promise that will load the zcl extensions. -### JS API: generator logic~loadTemplates(db, genTemplatesJson) ⇒ +### JS API: generator logic~loadTemplates(db, genTemplatesJsonArray) + +Api that loads an array of template JSON files or a single file if +you just pass in one String. + +**Kind**: inner method of [JS API: generator logic](#module*JS API* generator logic) + +| Param | Type | +| --------------------- | --------------- | +| db | \* | +| genTemplatesJsonArray | \* | + + + +### JS API: generator logic~loadSingleTemplate(db, genTemplatesJson) ⇒ Main API async function to load templates from a gen-template.json file. **Kind**: inner method of [JS API: generator logic](#module*JS API* generator logic) **Returns**: the loading context, contains: db, path, crc, packageId and templateData, or error -| Param | Type | Description | -| ---------------- | --------------- | --------------------- | -| db | \* | Database | -| genTemplatesJson | \* | Path to the JSON file | +| Param | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------- | +| db | \* | Database | +| genTemplatesJson | \* | Path to the JSON file or an array of paths to JSON file | @@ -10694,6 +10786,7 @@ This module provides the API to access zcl specific information. - [REST API: user data](#module*REST API* user data) - [~getComponentIdsByCluster(db, sessionId, clusterId, side)](#module*REST API* user data..getComponentIdsByCluster) ⇒ \* - [~httpGetSessionKeyValues(db)](#module*REST API* user data..httpGetSessionKeyValues) ⇒ + - [~httpGetNotifications(db)](#module*REST API* user data..httpGetNotifications) ⇒ - [~httpPostSaveSessionKeyValue(db)](#module*REST API* user data..httpPostSaveSessionKeyValue) ⇒ - [~httpPostCluster(db)](#module*REST API* user data..httpPostCluster) ⇒ - [~httpPostAttributeUpdate(db)](#module*REST API* user data..httpPostAttributeUpdate) ⇒ @@ -10739,6 +10832,19 @@ HTTP GET: session key values | ----- | --------------- | | db | \* | + + +### REST API: user data~httpGetNotifications(db) ⇒ + +HTTP GET: session get notifications + +**Kind**: inner method of [REST API: user data](#module*REST API* user data) +**Returns**: callback for the express uri registration + +| Param | Type | +| ----- | --------------- | +| db | \* | + ### REST API: user data~httpPostSaveSessionKeyValue(db) ⇒ @@ -11280,6 +11386,7 @@ This module provides the REST API to the user specific data. - [REST API: user data](#module*REST API* user data) - [~getComponentIdsByCluster(db, sessionId, clusterId, side)](#module*REST API* user data..getComponentIdsByCluster) ⇒ \* - [~httpGetSessionKeyValues(db)](#module*REST API* user data..httpGetSessionKeyValues) ⇒ + - [~httpGetNotifications(db)](#module*REST API* user data..httpGetNotifications) ⇒ - [~httpPostSaveSessionKeyValue(db)](#module*REST API* user data..httpPostSaveSessionKeyValue) ⇒ - [~httpPostCluster(db)](#module*REST API* user data..httpPostCluster) ⇒ - [~httpPostAttributeUpdate(db)](#module*REST API* user data..httpPostAttributeUpdate) ⇒ @@ -11325,6 +11432,19 @@ HTTP GET: session key values | ----- | --------------- | | db | \* | + + +### REST API: user data~httpGetNotifications(db) ⇒ + +HTTP GET: session get notifications + +**Kind**: inner method of [REST API: user data](#module*REST API* user data) +**Returns**: callback for the express uri registration + +| Param | Type | +| ----- | --------------- | +| db | \* | + ### REST API: user data~httpPostSaveSessionKeyValue(db) ⇒ @@ -14090,7 +14210,7 @@ Resolves with a promise that imports session key values. -## jsonDataLoader(db, state, sessionId) ⇒ +## jsonDataLoader(db, state, sessionId, packageMatch) ⇒ Given a state object, this method returns a promise that resolves with the succesfull writing into the database. @@ -14098,11 +14218,12 @@ with the succesfull writing into the database. **Kind**: global function **Returns**: a promise that resolves into a sessionId that was created. -| Param | Type | Description | -| --------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -| db | \* | | -| state | \* | | -| sessionId | \* | If null, then new session will get created, otherwise it loads the data into an existing session. Previous session data is not deleted. | +| Param | Type | Description | +| ------------ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| db | \* | | +| state | \* | | +| sessionId | \* | If null, then new session will get created, otherwise it loads the data into an existing session. Previous session data is not deleted. | +| packageMatch | \* | One of the package match strategies. See dbEnum.packageMatch | @@ -15035,37 +15156,11 @@ Load individual custom XML files. **Kind**: global function -| Param | Type | -| --------- | --------------- | -| db | \* | -| filePath | \* | -| sessionId | \* | - - - -## bindValidationScript(db, basePackageId) - -This function creates a validator function with signatuee fn(stringToValidateOn) - -**Kind**: global function - -| Param | Type | -| ------------- | --------------- | -| db | \* | -| basePackageId | \* | - - - -## getSchemaAndValidationScript(db, basePackageId) - -Returns an object with zclSchema and zclValidation elements. - -**Kind**: global function - -| Param | Type | -| ------------- | --------------- | -| db | \* | -| basePackageId | \* | +| Param | Type | Description | +| --------- | --------------- | ----------------------------------------------------- | +| db | \* | | +| filePath | \* | | +| sessionId | \* | Current session within which we're loading this file. | @@ -15749,18 +15844,6 @@ Parses the profiles xml. | db | \* | | ctx | \* | - - -## parseZclSchema(db) - -Parses the ZCL Schema - -**Kind**: global function - -| Param | Type | -| ----- | --------------- | -| db | \* | - ## parseFeatureFlags(db, packageId, featureFlags) ⇒ diff --git a/package.json b/package.json index a67127e41b..760482d212 100644 --- a/package.json +++ b/package.json @@ -66,17 +66,17 @@ "zapmeta": "node src-script/zap-start.js --logToStdout --zcl ./test/resource/meta/zcl.json --gen ./test/resource/meta/gen-test.json ./test/resource/test-meta.zap", "zaphelp": "node src-script/zap-start.js --help", "zap-dotdot": "node src-script/zap-start.js --logToStdout --zcl ./zcl-builtin/dotdot/library.xml", - "zap-devserver": "node src-script/zap-start.js server --allowCors --logToStdout --gen ./test/gen-template/zigbee/gen-templates.json --reuseZapInstance", - "matterzap-devserver": "node src-script/zap-start.js server --allowCors ---logToStdout --zcl ./zcl-builtin/matter/zcl.json --gen ./test/resource/meta/gen-test.json --reuseZapInstance", + "zigbeezap-devserver": "node src-script/zap-start.js server --stateDirectory ~/.zap/zigbee-server/ --allowCors --logToStdout --gen ./test/gen-template/zigbee/gen-templates.json --reuseZapInstance", + "matterzap-devserver": "node src-script/zap-start.js server --stateDirectory ~/.zap/matter-server/ --allowCors --logToStdout --zcl ./zcl-builtin/matter/zcl.json --gen ./test/resource/meta/gen-test.json --reuseZapInstance", "server": "node src-script/zap-start.js server --logToStdout --zcl ./zcl-builtin/silabs/zcl.json --zcl ./zcl-builtin/matter/zcl.json --gen ./test/gen-template/zigbee/gen-templates.json --reuseZapInstance", "stop": "node src-script/zap-start.js stop --reuseZapInstance", "status": "node src-script/zap-start.js status --reuseZapInstance", "self-check": "node src-script/zap-start.js selfCheck -g ./test/gen-template/zigbee/gen-templates.json", "post-import": "node src-script/zap-start.js convert --postImportScript test/resource/test-script.js test/resource/three-endpoint-device.zap -o test.zap", - "analyze": "node src-script/zap-start.js analyze -z ./zcl-builtin/silabs/zcl.json -g ./test/gen-template/zigbee/gen-templates.json ./test/resource/three-endpoint-device.zap -o ./tmp", + "analyze": "node src-script/zap-start.js analyze ./test/resource/three-endpoint-device.zap", "version": "node src-script/zap-start.js --version", "metafile-check": "node src-script/zap-validate-metafiles.js", - "test:gen": "npm run gen && npm run genmatter && npm run gendotdot && npm run genmeta", + "test:gen": "npm run gen && npm run genmatter && npm run gendotdot && npm run genmeta && npm run genmeta2", "gen": "node src-script/zap-generate.js --genResultFile --stateDirectory ~/.zap/gen -z ./zcl-builtin/silabs/zcl.json -g ./test/gen-template/zigbee/gen-templates.json -i ./test/resource/three-endpoint-device.zap -o ./tmp", "gen2": "node src-script/zap-generate.js --genResultFile -z ./zcl-builtin/silabs/zcl.json -g ./test/gen-template/zigbee/gen-templates.json -i ./test/resource/generation-test-file-1.zap -o ./tmp", "gen3": "node src-script/zap-generate.js --genResultFile --stateDirectory ~/.zap/gen3 -z ./zcl-builtin/dotdot/library.xml -g ./test/gen-template/zigbee/gen-templates.json -i ./test/resource/generation-test-file-1.zap -o ./tmp", diff --git a/src-electron/db/db-api.js b/src-electron/db/db-api.js index 50cf087ffb..8ca606a250 100644 --- a/src-electron/db/db-api.js +++ b/src-electron/db/db-api.js @@ -113,6 +113,16 @@ async function dbCommit(db) { }) } +/** + * Not an async function, simply returns a boolean value whether + * there is a currently active transaction. + * + * @returns true if transaction is active, false if not. + */ +function isTransactionActive() { + return inTransaction +} + /** * Returns a promise to execute a rollback of a transaction. * @@ -299,12 +309,13 @@ async function dbMultiInsert(db, sql, arrayOfArrays) { env.logSql('Preparing insert', sql, arrayOfArrays.length) let lastIds = [] let statement = db.prepare(sql, function (err) { - if (err) reject('Error While preparing sql command: ' + sql + ', ' + err) + if (err) + reject('Error while preparing sql statement: ' + sql + ', ' + err) for (const singleArray of arrayOfArrays) { statement.run(singleArray, (err2) => { if (err2) reject( - 'Error While running sql command: ' + + 'Error while running sql statement: ' + sql + ', values: ' + singleArray + @@ -316,7 +327,7 @@ async function dbMultiInsert(db, sql, arrayOfArrays) { } statement.finalize((err3) => { if (err3) - reject('Error While finalizing sql command: ' + sql + ', ' + err3) + reject('Error while finalizing sql statement: ' + sql + ', ' + err3) resolve(lastIds) }) }) @@ -578,6 +589,7 @@ function toInClause(value) { exports.dbBeginTransaction = dbBeginTransaction exports.dbCommit = dbCommit +exports.isTransactionActive = isTransactionActive exports.dbRollback = dbRollback exports.dbRemove = dbRemove exports.dbUpdate = dbUpdate diff --git a/src-electron/db/db-mapping.js b/src-electron/db/db-mapping.js index 0a233280fb..bd3be74366 100644 --- a/src-electron/db/db-mapping.js +++ b/src-electron/db/db-mapping.js @@ -505,6 +505,7 @@ exports.map = { packageRef: x.PACKAGE_REF, sessionRef: x.SESSION_REF, required: x.REQUIRED, + type: x.TYPE, } }, sessionLog: (x) => { diff --git a/src-electron/db/query-package.js b/src-electron/db/query-package.js index 3c743eb81c..0f979157d6 100644 --- a/src-electron/db/query-package.js +++ b/src-electron/db/query-package.js @@ -240,7 +240,7 @@ async function insertPathCrc( * @param {*} crc * @param {*} type * @param {*} [parentId=null] - * @returns Promise of an insert or update. + * @returns An object containing: id, existedPreviously */ async function registerTopLevelPackage( db, @@ -251,20 +251,28 @@ async function registerTopLevelPackage( category = null, description = null ) { - return getPackageByPathAndType(db, path, type).then((row) => { - if (row == null) { - return dbApi.dbInsert( - db, - ` + let row = await getPackageByPathAndType(db, path, type) + if (row == null) { + // Doesn't exist. We have to add it. + let id = await dbApi.dbInsert( + db, + ` INSERT INTO PACKAGE ( PATH, CRC, TYPE, PARENT_PACKAGE_REF, VERSION, CATEGORY, DESCRIPTION ) VALUES (?,?,?,?,?,?,?)`, - [path, crc, type, null, version, category, description] - ) - } else { - return Promise.resolve(row.id) + [path, crc, type, null, version, category, description] + ) + return { + id: id, + existedPreviously: false, } - }) + } else { + // Exists. We just return it. + return { + id: row.id, + existedPreviously: true, + } + } } /** @@ -448,6 +456,35 @@ async function getSessionPackages(db, sessionId) { .then((rows) => rows.map(dbMapping.map.sessionPackage)) } +/** + * Returns the session package IDs with types. + * @param {*} db + * @param {*} sessionId + * @returns The promise that resolves into an array of package IDs. + */ +async function getSessionPackagesWithTypes(db, sessionId) { + return dbApi + .dbAll( + db, + ` +SELECT + SP.PACKAGE_REF, + SP.SESSION_REF, + SP.REQUIRED, + P.TYPE +FROM + SESSION_PACKAGE AS SP +INNER JOIN + PACKAGE AS P +ON + SP.PACKAGE_REF = P.PACKAGE_ID +WHERE + SP.SESSION_REF = ? AND SP.ENABLED = 1`, + [sessionId] + ) + .then((rows) => rows.map(dbMapping.map.sessionPackage)) +} + /** * Returns all packages associated w/ a given sessionId * @param {*} db @@ -669,10 +706,14 @@ async function insertPackageExtensionDefault( return dbApi.dbMultiInsert( db, ` -INSERT INTO PACKAGE_EXTENSION_DEFAULT - (PACKAGE_EXTENSION_REF, ENTITY_CODE, ENTITY_QUALIFIER, PARENT_CODE, MANUFACTURER_CODE, VALUE) -VALUES - ( ?, ?, ?, ?, ?, ?) +INSERT INTO PACKAGE_EXTENSION_DEFAULT ( + PACKAGE_EXTENSION_REF, + ENTITY_CODE, + ENTITY_QUALIFIER, + PARENT_CODE, + MANUFACTURER_CODE, + VALUE +) VALUES ( ?, ?, ?, ?, ?, ? ) ON CONFLICT DO NOTHING `, defaultArray.map((d) => { @@ -707,10 +748,15 @@ async function insertPackageExtension( .dbMultiInsert( db, ` -INSERT INTO PACKAGE_EXTENSION - (PACKAGE_REF, ENTITY, PROPERTY, TYPE, CONFIGURABILITY, LABEL, GLOBAL_DEFAULT) -VALUES - (?, ?, ?, ?, ?, ?, ?) +INSERT INTO PACKAGE_EXTENSION ( + PACKAGE_REF, + ENTITY, + PROPERTY, + TYPE, + CONFIGURABILITY, + LABEL, + GLOBAL_DEFAULT +) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING`, propertyArray.map((p) => { return [ @@ -920,6 +966,7 @@ exports.registerTopLevelPackage = registerTopLevelPackage exports.updateVersion = updateVersion exports.insertSessionPackage = insertSessionPackage exports.getSessionPackages = getSessionPackages +exports.getSessionPackagesWithTypes = getSessionPackagesWithTypes exports.insertOptionsKeyValues = insertOptionsKeyValues exports.selectAllOptionsValues = selectAllOptionsValues exports.selectSpecificOptionValue = selectSpecificOptionValue diff --git a/src-electron/db/zap-schema.sql b/src-electron/db/zap-schema.sql index 8f395aaf1b..d0da18adb0 100644 --- a/src-electron/db/zap-schema.sql +++ b/src-electron/db/zap-schema.sql @@ -1118,16 +1118,15 @@ CREATE TABLE IF NOT EXISTS "SETTING" ( UNIQUE(CATEGORY, KEY) ); /* - Session Notification table -*/ - - CREATE TABLE IF NOT EXISTS "SESSION_NOTICE" ( - "SESSION_REF" integer, - "NOTICE_TYPE" text, - "NOTICE_MESSAGE" text, - "NOTICE_SEVERITY" integer, - "NOTICE_ORDER" integer primary key autoincrement, - "DISPLAY" integer, - foreign key (SESSION_REF) references SESSION(SESSION_ID) on delete cascade - ); -/* EO SCHEMA */ + Session Notification table + */ +CREATE TABLE IF NOT EXISTS "SESSION_NOTICE" ( + "SESSION_REF" integer, + "NOTICE_TYPE" text, + "NOTICE_MESSAGE" text, + "NOTICE_SEVERITY" integer, + "NOTICE_ORDER" integer primary key autoincrement, + "DISPLAY" integer, + foreign key (SESSION_REF) references SESSION(SESSION_ID) on delete cascade +); +/* EO SCHEMA */ \ No newline at end of file diff --git a/src-electron/generator/generation-engine.js b/src-electron/generator/generation-engine.js index 5c29d8bf7a..dbb89d5461 100644 --- a/src-electron/generator/generation-engine.js +++ b/src-electron/generator/generation-engine.js @@ -33,21 +33,22 @@ const e = require('express') /** * Given a path, it will read generation template object into memory. * - * @param {*} context.path - * @returns context.templates, context.crc + * @param {*} path + * @returns Object that contains: data, crc, templateData */ -async function loadGenTemplate(context) { - context.data = await fsPromise.readFile(context.path, 'utf8') - context.crc = util.checksum(context.data) - context.templateData = JSON.parse(context.data) +async function loadGenTemplateFromFile(path) { + let ret = {} + ret.data = await fsPromise.readFile(path, 'utf8') + ret.crc = util.checksum(ret.data) + ret.templateData = JSON.parse(ret.data) let requiredFeatureLevel = 0 - if ('requiredFeatureLevel' in context.templateData) { - requiredFeatureLevel = context.templateData.requiredFeatureLevel + if ('requiredFeatureLevel' in ret.templateData) { + requiredFeatureLevel = ret.templateData.requiredFeatureLevel } - let status = util.matchFeatureLevel(requiredFeatureLevel, context.path) + let status = util.matchFeatureLevel(requiredFeatureLevel, path) if (status.match) { - return context + return ret } else { throw status.message } @@ -114,7 +115,7 @@ async function loadTemplateOptionsFromJsonFile( * @returns promise that resolves with the same context passed in, except packageId added to it */ async function recordTemplatesPackage(context) { - context.packageId = await queryPackage.registerTopLevelPackage( + let topLevel = await queryPackage.registerTopLevelPackage( context.db, context.path, context.crc, @@ -124,6 +125,9 @@ async function recordTemplatesPackage(context) { context.templateData.description ) + context.packageId = topLevel.id + if (topLevel.existedPreviously) return context + let promises = [] env.logDebug(`Loading ${context.templateData.templates.length} templates.`) @@ -484,6 +488,7 @@ async function loadTemplates( } if (genTemplatesJsonArray != null && genTemplatesJsonArray.length > 0) { for (let jsonFile of genTemplatesJsonArray) { + if (jsonFile == null || jsonFile == '') continue let ctx = await loadSingleTemplate(db, jsonFile) if (ctx.error) { if (options.failOnLoadingError) globalCtx.error = ctx.error @@ -496,10 +501,15 @@ async function loadTemplates( } } return globalCtx - } else { + } else if (genTemplatesJsonArray != null) { let ctx = await loadSingleTemplate(db, genTemplatesJsonArray) ctx.packageIds = [ctx.packageId] return ctx + } else { + // We didn't load anything, we don't return anything. + return { + nop: true, + } } } @@ -519,6 +529,7 @@ async function loadSingleTemplate(db, genTemplatesJson) { env.logWarning(context.error) return Promise.resolve(context) } + let isTransactionAlreadyExisting = dbApi.isTransactionActive() let file = path.resolve(genTemplatesJson) if (!fs.existsSync(file)) { @@ -527,16 +538,16 @@ async function loadSingleTemplate(db, genTemplatesJson) { return context } context.path = file - await dbApi.dbBeginTransaction(db) + if (!isTransactionAlreadyExisting) await dbApi.dbBeginTransaction(db) try { - context = await loadGenTemplate(context) + Object.assign(context, await loadGenTemplateFromFile(file)) context = await recordTemplatesPackage(context) return context } catch (err) { - env.logInfo(`Can not read templates from: ${context.file}`) + env.logInfo(`Can not read templates from: ${file}`) throw err } finally { - dbApi.dbCommit(db) + if (!isTransactionAlreadyExisting) await dbApi.dbCommit(db) } } @@ -846,7 +857,6 @@ async function generateAndWriteFiles( appendedPath = templateGeneratorOptions.appendDirectory } - console.log(`Appended path: ${appendedPath}`) if (appendedPath != null) { outputDirectory = path.join(outputDirectory, appendedPath) } diff --git a/src-electron/importexport/import-json.js b/src-electron/importexport/import-json.js index b0beba8ca6..37e4d8bda6 100644 --- a/src-electron/importexport/import-json.js +++ b/src-electron/importexport/import-json.js @@ -22,6 +22,7 @@ const queryPackage = require('../db/query-package.js') const queryImpexp = require('../db/query-impexp.js') const querySession = require('../db/query-session.js') const zclLoader = require('../zcl/zcl-loader.js') +const generationEngine = require('../generator/generation-engine') /** * Resolves with a promise that imports session key values. @@ -57,10 +58,43 @@ function getPkgPath(pkg, zapFilePath) { } } +/** + * Auto-load package. If succesful it returns an object. + * Otherwise it throws an exception. + * + * @param {*} db + * @param {*} pkg + * @param {*} absPath + * @returns object containing packageId and packageType. + */ +async function autoLoadPackage(db, pkg, absPath) { + if (pkg.type === dbEnum.packageType.zclProperties) { + let ctx = await zclLoader.loadZcl(db, absPath) + return { + packageId: ctx.packageId, + packageType: pkg.type, + } + } else if (pkg.type === dbEnum.packageType.genTemplatesJson) { + let ctx = await generationEngine.loadTemplates(db, [absPath], { + failOnLoadingError: true, + }) + if (ctx.error) throw new Error(ctx.error) + return { + packageId: ctx.packageId, + packageType: pkg.type, + } + } else { + throw new Error( + `Auto-loading of package type "${pkg.type}" is not implemented.` + ) + } +} + // Resolves into a { packageId:, packageType:} // object, pkg has`path`, `version`, `type`. It can ALSO have pathRelativity. If pathRelativity is missing // path is considered absolute. -async function importSinglePackage(db, sessionId, pkg, zapFilePath) { +async function importSinglePackage(db, pkg, zapFilePath, packageMatch) { + let autoloading = true let absPath = getPkgPath(pkg, zapFilePath) let pkgId = await queryPackage.getPackageIdByPathAndTypeAndVersion( db, @@ -77,6 +111,12 @@ async function importSinglePackage(db, sessionId, pkg, zapFilePath) { } } + // No perfect match. + // We will attempt to simply load up the package as it is listed in the file. + if (autoloading && !(packageMatch === dbEnum.packageMatch.ignore)) { + return await autoLoadPackage(db, pkg, absPath) + } + // Now we have to perform the guessing logic. env.logDebug( 'Packages from the file did not match loaded packages making best bet.' @@ -172,9 +212,8 @@ async function importSinglePackage(db, sessionId, pkg, zapFilePath) { } // Resolves an array of { packageId:, packageType:} objects into { zclPackageId: id, templateIds: [] } -function convertPackageResult(sessionId, data) { +function convertPackageResult(data) { let ret = { - sessionId: sessionId, zclPackageId: null, templateIds: [], optionalIds: [], @@ -193,16 +232,16 @@ function convertPackageResult(sessionId, data) { } // Returns a promise that resolves into an object containing: packageId and otherIds -async function importPackages(db, sessionId, packages, zapFilePath) { +async function importPackages(db, packages, zapFilePath, packageMatch) { let allQueries = [] if (packages != null) { env.logDebug(`Loading ${packages.length} packages`) packages.forEach((p) => { - allQueries.push(importSinglePackage(db, sessionId, p, zapFilePath)) + allQueries.push(importSinglePackage(db, p, zapFilePath, packageMatch)) }) } let data = await Promise.all(allQueries) - return convertPackageResult(sessionId, data) + return convertPackageResult(data) } async function importEndpointTypes( @@ -318,20 +357,24 @@ async function importEndpointTypes( * @param {*} sessionId If null, then new session will get * created, otherwise it loads the data into an * existing session. Previous session data is not deleted. + * @param {*} packageMatch One of the package match strategies. See dbEnum.packageMatch * @returns a promise that resolves into a sessionId that was created. */ -async function jsonDataLoader(db, state, sessionId) { +async function jsonDataLoader(db, state, sessionId, packageMatch) { // Loading all packages before custom xml to make sure clusterExtensions are // handled properly - let mainPackages = state.package.filter( - (pkg) => pkg.type != dbEnum.packageType.zclXmlStandalone + let topLevelPackages = state.package.filter( + (pkg) => + pkg.type == dbEnum.packageType.zclProperties || + pkg.type == dbEnum.packageType.genTemplatesJson ) let mainPackageData = await importPackages( db, - sessionId, - mainPackages, - state.filePath + topLevelPackages, + state.filePath, + packageMatch ) + mainPackageData.sessionId = sessionId let mainPackagePromise = [] mainPackagePromise.push( @@ -403,10 +446,11 @@ async function jsonDataLoader(db, state, sessionId) { let standAlonePackageData = await importPackages( db, - sessionId, zclXmlStandAlonePackages, - state.filePath + state.filePath, + packageMatch ) + standAlonePackageData.sessionId = sessionId // packageData: { sessionId, packageId, otherIds, optionalIds} let optionalPackagePromises = [] diff --git a/src-electron/importexport/import.js b/src-electron/importexport/import.js index ca1e3838dd..686f386b9c 100644 --- a/src-electron/importexport/import.js +++ b/src-electron/importexport/import.js @@ -28,6 +28,7 @@ const dbApi = require('../db/db-api.js') const querySession = require('../db/query-session.js') const env = require('../util/env') const script = require('../util/script') +const dbEnum = require('../../src-shared/db-enum') /** * Reads the data from the file and resolves with the state object if all is good. @@ -85,6 +86,7 @@ async function importDataFromFile( sessionId: null, defaultZclMetafile: env.builtinSilabsZclMetafile(), postImportScript: null, + packageMatch: dbEnum.packageMatch.fuzzy, } ) { try { @@ -96,7 +98,7 @@ async function importDataFromFile( } else { sid = options.sessionId } - let loaderResult = await state.loader(db, state, sid) + let loaderResult = await state.loader(db, state, sid, options.packageMatch) if (options.postImportScript != null) { await executePostImportScript( db, @@ -106,7 +108,7 @@ async function importDataFromFile( } return loaderResult } finally { - dbApi.dbCommit(db) + await dbApi.dbCommit(db) } } diff --git a/src-electron/main-process/startup.js b/src-electron/main-process/startup.js index 3fee8acbc8..a13cf97f25 100644 --- a/src-electron/main-process/startup.js +++ b/src-electron/main-process/startup.js @@ -204,6 +204,7 @@ async function startConvert(argv, options) { let importResult = await importJs.importDataFromFile(db, singlePath, { defaultZclMetafile: argv.zclProperties, postImportScript: argv.postImportScript, + packageMatch: argv.packageMatch, }) let sessionId = importResult.sessionId @@ -373,6 +374,7 @@ async function startAnalyze(argv, options) { .importDataFromFile(db, singlePath, { defaultZclMetafile: argv.zclProperties, postImportScript: argv.postImportScript, + packageMatch: argv.packageMatch, }) .then((importResult) => util.sessionReport(db, importResult.sessionId)) .then((report) => { @@ -467,7 +469,9 @@ async function startSelfCheck( failOnLoadingError: !argv.noLoadingFailure, } ) - if (ctx.error) { + if (ctx.nop) { + options.logger(` 👉 no generation template packages loaded`) + } else if (ctx.error) { options.logger(` ⚠️ ${ctx.error}`) } else { options.logger( @@ -487,8 +491,8 @@ async function startSelfCheck( async function generateSingleFile( db, - f, - templatePackageId, + zapFile, + templatePackageId, // This may be null if none is preloaded. outputPattern, index, options = { @@ -496,27 +500,35 @@ async function generateSingleFile( zcl: env.builtinSilabsZclMetafile(), template: env.builtinTemplateMetafile(), postImportScript: null, + packageMatch: dbEnum.packageMatch.fuzzy, } ) { let hrstart = process.hrtime.bigint() let sessionId let output - if (f === BLANK_SESSION) { + if (zapFile === BLANK_SESSION) { options.logger(`👉 using empty configuration`) sessionId = await querySession.createBlankSession(db) output = outputPattern } else { - options.logger(`👉 using input file: ${f}`) - let importResult = await importJs.importDataFromFile(db, f, { + options.logger(`👉 using input file: ${zapFile}`) + let importResult = await importJs.importDataFromFile(db, zapFile, { defaultZclMetafile: options.zcl, postImportScript: options.postImportScript, + packageMatch: options.packageMatch, }) sessionId = importResult.sessionId - output = outputFile(f, outputPattern, index) + output = outputFile(zapFile, outputPattern, index) } options.logger(`👉 using output destination: ${output}`) - await util.initializeSessionPackage(db, sessionId, options) + let sessPkg = await util.initializeSessionPackage(db, sessionId, options) + let usedTemplatePackageId = templatePackageId + for (let pkg of sessPkg) { + if (pkg.type === dbEnum.packageType.genTemplatesJson) { + usedTemplatePackageId = pkg.packageRef + } + } let nsDuration = process.hrtime.bigint() - hrstart options.logger(`🕐 File loading time: ${util.duration(nsDuration)}`) @@ -525,14 +537,14 @@ async function generateSingleFile( let genResult = await generatorEngine.generateAndWriteFiles( db, sessionId, - templatePackageId, + usedTemplatePackageId, output, options ) if (genResult.hasErrors) { console.log(JSON.stringify(genResult.errors)) - throw new Error(`Generation failed: ${f}`) + throw new Error(`Generation failed: ${zapFile}`) } return genResult @@ -579,7 +591,7 @@ async function startGeneration(argv, options) { throw ctx.error } - let packageId = ctx.packageId + let globalTemplatePackageId = ctx.packageId let files = gatherFiles(zapFiles, { suffix: '.zap', doBlank: true }) if (files.length == 0) { @@ -594,12 +606,20 @@ async function startGeneration(argv, options) { options.skipPostGeneration = skipPostGeneration options.postImportScript = argv.postImportScript options.appendGenerationSubdirectory = argv.appendGenerationSubdirectory + options.packageMatch = argv.packageMatch let nsDuration = process.hrtime.bigint() - hrstart options.logger(`🕐 Setup time: ${util.duration(nsDuration)} `) await util.executePromisesSequentially(files, (f, index) => - generateSingleFile(mainDb, f, packageId, output, index, options) + generateSingleFile( + mainDb, + f, + globalTemplatePackageId, + output, + index, + options + ) ) if (options.quitFunction != null) options.quitFunction() diff --git a/src-electron/util/args.ts b/src-electron/util/args.ts index ede3571b46..67130a9f2a 100644 --- a/src-electron/util/args.ts +++ b/src-electron/util/args.ts @@ -218,6 +218,11 @@ export function processCommandLineArguments(argv: string[]) { type: 'boolean', default: false, }) + .option('packageMatch', { + desc: "Determines how to associate with packages in zap file. 'strict' will cause loading to fail if specified package files are not found, 'fuzzy' will associate with similar packages.", + choices: ['fuzzy', 'strict'], + default: 'fuzzy', + }) .option('results', { desc: 'Specifying the output YAML file to capture convert results.', type: 'string', diff --git a/src-electron/util/util.js b/src-electron/util/util.js index 29dedc04a5..8374621856 100644 --- a/src-electron/util/util.js +++ b/src-electron/util/util.js @@ -176,34 +176,32 @@ async function initializeSessionPackage( promises.push(genTemplateJsonPromise) } - return Promise.all(promises) - .then(() => queryPackage.getSessionPackages(db, sessionId)) - .then((packages) => { - let p = packages.map((pkg) => - queryPackage - .selectAllDefaultOptions(db, pkg.packageRef) - .then((optionDefaultsArray) => - Promise.all( - optionDefaultsArray.map((optionDefault) => { - return queryPackage - .selectOptionValueByOptionDefaultId( - db, - optionDefault.optionRef - ) - .then((option) => { - return querySession.insertSessionKeyValue( - db, - sessionId, - option.optionCategory, - option.optionCode - ) - }) + await Promise.all(promises) + + let packages = await queryPackage.getSessionPackagesWithTypes(db, sessionId) + let p = packages.map((pkg) => + queryPackage + .selectAllDefaultOptions(db, pkg.packageRef) + .then((optionDefaultsArray) => + Promise.all( + optionDefaultsArray.map((optionDefault) => { + return queryPackage + .selectOptionValueByOptionDefaultId(db, optionDefault.optionRef) + .then((option) => { + return querySession.insertSessionKeyValue( + db, + sessionId, + option.optionCategory, + option.optionCode + ) }) - ) - ) + }) + ) ) - return Promise.all(p).then(() => packages) - }) + ) + + await Promise.all(p) + return packages } /** diff --git a/src-electron/zcl/zcl-loader-silabs.js b/src-electron/zcl/zcl-loader-silabs.js index fa30d46895..7d2c1ea3c5 100644 --- a/src-electron/zcl/zcl-loader-silabs.js +++ b/src-electron/zcl/zcl-loader-silabs.js @@ -70,10 +70,6 @@ async function collectDataFromJsonFile(metadataFile, data) { f = util.locateRelativeFilePath(fileLocations, obj.zclSchema) if (f != null) returnObject.zclSchema = f - // Zcl Validation Script - f = util.locateRelativeFilePath(fileLocations, obj.zclValidation) - if (f != null) returnObject.zclValidation = f - // General options // Note that these values when put into OPTION_CODE will generally be converted to lowercase. if (obj.options) { @@ -216,10 +212,6 @@ async function collectDataFromPropertiesFile(metadataFile, data) { f = util.locateRelativeFilePath(fileLocations, zclProps.zclSchema) if (f != null) returnObject.zclSchema = f - // Zcl Validation Script - f = util.locateRelativeFilePath(fileLocations, zclProps.zclValidation) - if (f != null) returnObject.zclValidation = f - // General options // Note that these values when put into OPTION_CODE will generally be converted to lowercase. if (zclProps.options) { @@ -1908,40 +1900,6 @@ async function parseProfilesData(db, packageId, profilesXml) { ) } -/** - * Parses the ZCL Schema - * @param {*} db - */ -async function parseZclSchema(db, packageId, zclSchema, zclValidation) { - let content = await fsp.readFile(zclSchema) - let info = { - filePath: zclSchema, - data: content, - crc: util.checksum(content), - } - await zclLoader.qualifyZclFile( - db, - info, - packageId, - dbEnum.packageType.zclSchema, - false - ) - content = await fsp.readFile(zclValidation) - info = { - filePath: zclValidation, - data: content, - crc: util.checksum(content), - } - - return zclLoader.qualifyZclFile( - db, - info, - packageId, - dbEnum.packageType.zclValidation, - false - ) -} - /** * Inside the `zcl.json` can be a `featureFlags` key, which is * a general purpose object. It contains keys, that map to objects. @@ -2161,12 +2119,7 @@ async function parseBoolDefaults(db, pkgRef, booleanCategories) { * @param {*} filePath * @returns Promise of a loaded file. */ -async function loadIndividualSilabsFile( - db, - filePath, - boundValidator, - sessionId -) { +async function loadIndividualSilabsFile(db, filePath, sessionId) { try { let fileContent = await fsp.readFile(filePath) let data = { @@ -2183,16 +2136,10 @@ async function loadIndividualSilabsFile( true ) let pkgId = result.packageId - if (boundValidator != null && fileContent != null) { - result.validation = boundValidator(fileContent) - } if (result.data) { result.result = await util.parseXml(result.data) delete result.data } - if (result.validation && result.validation.isValid == false) { - throw new Error('Validation Failed') - } let sessionPackages = await queryPackage.getSessionZclPackages( db, sessionId @@ -2257,11 +2204,14 @@ async function loadSilabsZcl(db, metafile, isJson = false) { metadataFile: metafile, db: db, } + let isTransactionAlreadyExisting = dbApi.isTransactionActive() env.logDebug(`Loading Silabs zcl file: ${metafile}`) if (!fs.existsSync(metafile)) { throw new Error(`Can't locate: ${metafile}`) } - await dbApi.dbBeginTransaction(db) + + if (!isTransactionAlreadyExisting) await dbApi.dbBeginTransaction(db) + try { Object.assign(ctx, await util.readFileContentAndCrc(ctx.metadataFile)) ctx.packageId = await zclLoader.recordToplevelPackage( @@ -2342,9 +2292,6 @@ async function loadSilabsZcl(db, metafile, isJson = false) { if (ctx.defaults) { await parseDefaults(db, ctx.packageId, ctx.defaults) } - if (ctx.zclSchema && ctx.zclValidation) { - await parseZclSchema(db, ctx.packageId, ctx.zclSchema, ctx.zclValidation) - } if (ctx.featureFlags) { await parseFeatureFlags(db, ctx.packageId, ctx.featureFlags) } @@ -2355,7 +2302,7 @@ async function loadSilabsZcl(db, metafile, isJson = false) { env.logError(err) throw err } finally { - dbApi.dbCommit(db) + if (!isTransactionAlreadyExisting) await dbApi.dbCommit(db) } return ctx } diff --git a/src-electron/zcl/zcl-loader.js b/src-electron/zcl/zcl-loader.js index 62111da5f5..c6bd2da737 100644 --- a/src-electron/zcl/zcl-loader.js +++ b/src-electron/zcl/zcl-loader.js @@ -21,18 +21,11 @@ const queryPackage = require('../db/query-package') const queryCommand = require('../db/query-command') const queryLoader = require('../db/query-loader') const dbEnum = require('../../src-shared/db-enum') -const fsp = fs.promises const sLoad = require('./zcl-loader-silabs') const dLoad = require('./zcl-loader-dotdot') const queryZcl = require('../db/query-zcl') const queryDeviceType = require('../db/query-device-type') const env = require('../util/env') -const nativeRequire = require('../util/native-require') -const util = require('../util/util') - -const defaultValidator = (zclData) => { - return [] -} /** * Records the toplevel package information and resolves into packageId @@ -42,12 +35,13 @@ const defaultValidator = (zclData) => { * @returns packageId */ async function recordToplevelPackage(db, metadataFile, crc) { - return queryPackage.registerTopLevelPackage( + let topLevel = await queryPackage.registerTopLevelPackage( db, metadataFile, crc, dbEnum.packageType.zclProperties ) + return topLevel.id } /** @@ -129,27 +123,12 @@ async function loadZcl(db, metadataFile) { * * @param {*} db * @param {*} filePath - * @param {*} sessionId + * @param {*} sessionId Current session within which we're loading this file. */ async function loadIndividualFile(db, filePath, sessionId) { - let zclPropertiesPackages = await queryPackage.getSessionPackagesByType( - db, - sessionId, - dbEnum.packageType.zclProperties - ) - - let validator - if (zclPropertiesPackages.length == 0) { - env.logDebug(`Unable to find a validator for project, skipping validator`) - // Return an function that returns an empty array - validator = defaultValidator - } else { - validator = await bindValidationScript(db, zclPropertiesPackages[0].id) - } - let ext = path.extname(filePath) if (ext == '.xml') { - return sLoad.loadIndividualSilabsFile(db, filePath, validator, sessionId) + return sLoad.loadIndividualSilabsFile(db, filePath, sessionId) } else { let err = new Error( `Unable to read file: ${filePath}. Expecting an XML file with ZCL clusters.` @@ -159,67 +138,6 @@ async function loadIndividualFile(db, filePath, sessionId) { } } -/** - * This function creates a validator function with signatuee fn(stringToValidateOn) - * - * @param {*} db - * @param {*} basePackageId - */ -async function bindValidationScript(db, basePackageId) { - try { - let data = await getSchemaAndValidationScript(db, basePackageId) - - if ( - !(dbEnum.packageType.zclSchema in data) || - !(dbEnum.packageType.zclValidation in data) - ) { - return defaultValidator - } else { - let zclSchema = data[dbEnum.packageType.zclSchema] - let zclValidation = data[dbEnum.packageType.zclValidation] - let module = nativeRequire(zclValidation) - let validateZclFile = module.validateZclFile - - env.logDebug(`Reading individual file: ${zclSchema}`) - let schemaFileContent = await fsp.readFile(zclSchema) - return validateZclFile.bind(null, schemaFileContent) - } - } catch (err) { - env.logError(`Error loading package specific validator: ${err}`) - return defaultValidator - } -} - -/** - * Returns an object with zclSchema and zclValidation elements. - * @param {*} db - * @param {*} basePackageId - */ -async function getSchemaAndValidationScript(db, basePackageId) { - let promises = [] - promises.push( - queryPackage.getPackagesByParentAndType( - db, - basePackageId, - dbEnum.packageType.zclSchema - ) - ) - promises.push( - queryPackage.getPackagesByParentAndType( - db, - basePackageId, - dbEnum.packageType.zclValidation - ) - ) - let data = await Promise.all(promises) - return data.reduce((result, item) => { - if (item.length >= 1) { - result[item[0].type] = item[0].path - } - return result - }, {}) -} - /** * Promises to qualify whether zcl file needs to be reloaded. * If yes, the it will resolve with {filePath, data, packageId} diff --git a/src-script/zap-uitest.js b/src-script/zap-uitest.js index 437ee07b71..b9b5a3bf72 100755 --- a/src-script/zap-uitest.js +++ b/src-script/zap-uitest.js @@ -52,7 +52,7 @@ if (cypressMode == '-?') { let svrCmd let fixturesConfig if (testsType == 'zigbee') { - svrCmd = 'zap-devserver' + svrCmd = 'zigbeezap-devserver' fixturesConfig = '' } else if (testsType == 'matter') { svrCmd = 'matterzap-devserver' diff --git a/src-shared/db-enum.js b/src-shared/db-enum.js index 8f3dd97152..b7461d24cc 100644 --- a/src-shared/db-enum.js +++ b/src-shared/db-enum.js @@ -26,7 +26,6 @@ exports.packageType = { zclXmlStandalone: 'zcl-xml-standalone', sqlSchema: 'sql-schema', zclSchema: 'zcl-schema', - zclValidation: 'zcl-validation-script', genTemplatesJson: 'gen-templates-json', genSingleTemplate: 'gen-template', genHelper: 'gen-helper', @@ -177,3 +176,9 @@ exports.helperCategory = { matter: 'matter', meta: 'meta', } + +exports.packageMatch = { + fuzzy: 'fuzzy', // This mechanism will attempt to match the ones from zap file, then give up and do fuzzy match if it fails. + strict: 'strict', // This mechanism will ONLY use the records of packages in the .zap file. + ignore: 'ignore', // This mechanism will completely ignore the use of packages in the .zap file. +} diff --git a/test/custom-cluster.test.js b/test/custom-cluster.test.js index 9361f5d1a5..ef69916c7f 100644 --- a/test/custom-cluster.test.js +++ b/test/custom-cluster.test.js @@ -23,12 +23,10 @@ const zclLoader = require('../src-electron/zcl/zcl-loader') const env = require('../src-electron/util/env') const testUtil = require('./test-util') const testQuery = require('./test-query') -const querySession = require('../src-electron/db/query-session') const queryPackage = require('../src-electron/db/query-package') const queryConfig = require('../src-electron/db/query-config') const queryDeviceType = require('../src-electron/db/query-device-type') -const util = require('../src-electron/util/util') let db let sid let mfgCode = 0xbead diff --git a/test/gen-matter.test.js b/test/gen-matter.test.js index 099a78781a..dd18b4a54e 100644 --- a/test/gen-matter.test.js +++ b/test/gen-matter.test.js @@ -22,16 +22,14 @@ const path = require('path') const genEngine = require('../src-electron/generator/generation-engine.js') const env = require('../src-electron/util/env.ts') const dbApi = require('../src-electron/db/db-api.js') -const queryPackage = require('../src-electron/db/query-package.js') const queryAttribute = require('../src-electron/db/query-attribute.js') const querySession = require('../src-electron/db/query-session.js') const queryZcl = require('../src-electron/db/query-zcl.js') -const utilJs = require('../src-electron/util/util.js') const zclLoader = require('../src-electron/zcl/zcl-loader.js') -const helperZap = require('../src-electron/generator/helper-zap.js') const importJs = require('../src-electron/importexport/import.js') const testUtil = require('./test-util.js') const testQuery = require('./test-query.js') +const dbEnum = require('../src-shared/db-enum') let db let templateContext diff --git a/test/resource/matter-test.zap b/test/resource/matter-test.zap index 02049717ce..7d73bfbb76 100644 --- a/test/resource/matter-test.zap +++ b/test/resource/matter-test.zap @@ -18,15 +18,17 @@ "package": [ { "pathRelativity": "relativeToZap", - "path": "../../zcl-builtin/silabs/zcl.json", - "version": "ZCL Test Data", - "type": "zcl-properties" + "path": "../../zcl-builtin/matter/zcl.json", + "type": "zcl-properties", + "category": "matter", + "version": 1, + "description": "Matter Test Data" }, { "pathRelativity": "relativeToZap", - "path": "../gen-template/zigbee/gen-templates.json", - "version": "test-v1", - "type": "gen-templates-json" + "path": "../gen-template/matter/gen-test.json", + "type": "gen-templates-json", + "version": "test-matter" } ], "endpointTypes": [ diff --git a/test/server-bare.test.js b/test/server-bare.test.js index 22ef7352c3..4233813986 100644 --- a/test/server-bare.test.js +++ b/test/server-bare.test.js @@ -209,21 +209,17 @@ describe('Session specific tests', () => { // We save and then load, which creates a new session. test( 'save into a file and load from file', - () => { + async () => { let f = path.join(env.appDirectory(), 'test-output.json') if (fs.existsSync(f)) fs.unlinkSync(f) expect(fs.existsSync(f)).toBeFalsy() - return exportJs - .exportDataIntoFile(db, sessionId, f) - .then(() => { - expect(fs.existsSync(f)).toBeTruthy() - }) - .then(() => importJs.importDataFromFile(db, f)) - .then((importResult) => { - secondSessionId = importResult.sessionId - fs.unlinkSync(f) - return Promise.resolve(1) - }) + await exportJs.exportDataIntoFile(db, sessionId, f) + expect(fs.existsSync(f)).toBeTruthy() + let importResult = await importJs.importDataFromFile(db, f, { + packageMatch: dbEnum.packageMatch.ignore, + }) + secondSessionId = importResult.sessionId + fs.unlinkSync(f) }, testUtil.timeout.medium() )