-
Notifications
You must be signed in to change notification settings - Fork 5
Support non node environment validation #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
24b5db5
a2fdb64
43fe0c7
a216969
f86848b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /*************************************************************************************** | ||
| * (c) 2026 Adobe. All rights reserved. | ||
| * This file is licensed to you under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. You may obtain a copy | ||
| * of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software distributed under | ||
| * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
| * OF ANY KIND, either express or implied. See the License for the specific language | ||
| * governing permissions and limitations under the License. | ||
| ****************************************************************************************/ | ||
|
|
||
| // Recursively scans a directory and returns an array of relative file path strings. | ||
| // Node-only -- uses fs and path. Not suitable for browser environments. | ||
| // | ||
| // Example: for an extension layout like | ||
| // extension.json | ||
| // src/view/configuration.html | ||
| // src/view/events/click.html | ||
| // src/lib/main.js | ||
| // the returned array is e.g. | ||
| // ['extension.json', 'src/view/configuration.html', 'src/view/events/click.html', 'src/lib/main.js'] | ||
|
|
||
| 'use strict'; | ||
| var fs = require('fs'); | ||
| var pathUtil = require('path'); | ||
|
|
||
| var gatherFilesInNodeEnvironment = function(dir, root, result) { | ||
| root = root || dir; | ||
| result = result || []; | ||
| var entries = fs.readdirSync(dir); | ||
| entries.forEach(function(entry) { | ||
| var fullPath = pathUtil.join(dir, entry); | ||
| var relPath = pathUtil.relative(root, fullPath); | ||
| if (fs.statSync(fullPath).isDirectory()) { | ||
| gatherFilesInNodeEnvironment(fullPath, root, result); | ||
| } else { | ||
| result.push(relPath); | ||
| } | ||
| }); | ||
| return result; | ||
| }; | ||
|
|
||
| module.exports = gatherFilesInNodeEnvironment; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| /*************************************************************************************** | ||
| * (c) 2026 Adobe. All rights reserved. | ||
| * This file is licensed to you under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. You may obtain a copy | ||
| * of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software distributed under | ||
| * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
| * OF ANY KIND, either express or implied. See the License for the specific language | ||
| * governing permissions and limitations under the License. | ||
| ****************************************************************************************/ | ||
|
|
||
| // Validates an extension descriptor against its JSON schema and a provided file list. | ||
| // Portable -- no Node-specific APIs. Safe to use in browser environments. | ||
| // Accepts (extensionDescriptor, fileList) where fileList is an array of relative path strings. | ||
| // Returns undefined if valid, or an error string on the first problem encountered. | ||
|
|
||
| 'use strict'; | ||
| var validateSchema = require('./validateSchema'); | ||
| var validateFiles = require('./validateFiles'); | ||
|
|
||
| module.exports = function(extensionDescriptor, fileList) { | ||
| var error = validateSchema(extensionDescriptor); | ||
| if (error) return error; | ||
|
|
||
| error = validateFiles(extensionDescriptor, fileList); | ||
| if (error) return error; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| /*************************************************************************************** | ||
| * (c) 2026 Adobe. All rights reserved. | ||
| * This file is licensed to you under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. You may obtain a copy | ||
| * of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software distributed under | ||
| * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
| * OF ANY KIND, either express or implied. See the License for the specific language | ||
| * governing permissions and limitations under the License. | ||
| ****************************************************************************************/ | ||
|
|
||
| // Validates that files referenced by an extension descriptor exist in a provided file list. | ||
| // Portable -- no Node-specific APIs. Safe to use in browser environments. | ||
| // Accepts (extensionDescriptor, fileList) where fileList is an array of relative path strings. | ||
| // Returns undefined if valid, or an error string if not. | ||
|
|
||
| 'use strict'; | ||
|
|
||
| var stripQueryAndAnchor = function(path) { | ||
| return path.split('?').shift().split('#').shift(); | ||
| }; | ||
|
|
||
| var joinPath = function() { | ||
| return [].slice.call(arguments).filter(Boolean).join('/').replace(/\/+/g, '/'); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should probably fix this to work for Windows as well.
On windows, the fileSet would contain Looks like the old code avoided this because it used In ...or normalize the file list in |
||
| }; | ||
|
|
||
| var validateViewBasePath = function(extensionDescriptor, fileSet, fileList) { | ||
| var viewBasePath = extensionDescriptor.viewBasePath; | ||
| if (!viewBasePath) return; | ||
|
|
||
| var viewBaseNorm = viewBasePath.replace(/\/+$/, ''); | ||
| if (fileSet.has(viewBaseNorm)) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI - AI found a non-urgent edge case... This checks if viewBaseNorm appears as an exact file in the set. If it does, it's assumed to be a file (not a directory). This is a reasonable heuristic for real-world extension packages. However, the redundant p === viewBaseNorm check at line 38 inside the some() can never succeed at that point (if the path were in the set as a file, we'd have already returned an error). Not harmful, but slightly confusing. |
||
| return 'The referenced viewBasePath ' + viewBasePath + ' is either not a directory or is empty.'; | ||
| } | ||
|
|
||
| var hasFileUnderPath = fileList.some(function(p) { | ||
| return p === viewBaseNorm || p.indexOf(viewBaseNorm + '/') === 0; | ||
| }); | ||
| if (!hasFileUnderPath) { | ||
| return 'The referenced viewBasePath ' + viewBasePath + ' is either not a directory or is empty.'; | ||
| } | ||
| }; | ||
|
|
||
| var validateFileList = function(extensionDescriptor, fileSet) { | ||
| var paths = []; | ||
| var platform = extensionDescriptor.platform; | ||
| var viewBase = extensionDescriptor.viewBasePath; | ||
|
|
||
| if (!platform) { | ||
| return 'the required property "platform" is missing.'; | ||
| } | ||
|
|
||
| if (extensionDescriptor.main) { | ||
| paths.push(extensionDescriptor.main); | ||
| } | ||
|
|
||
| if (extensionDescriptor.configuration) { | ||
| paths.push(joinPath(viewBase, stripQueryAndAnchor(extensionDescriptor.configuration.viewPath))); | ||
| } | ||
|
|
||
| ['events', 'conditions', 'actions', 'dataElements'].forEach(function(type) { | ||
| var features = extensionDescriptor[type]; | ||
| if (features) { | ||
| features.forEach(function(feature) { | ||
| if (feature.viewPath) { | ||
| paths.push(joinPath(viewBase, stripQueryAndAnchor(feature.viewPath))); | ||
| } | ||
| if (platform === 'web') { | ||
| paths.push(feature.libPath); | ||
| } | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| for (var i = 0; i < paths.length; i++) { | ||
| if (!fileSet.has(paths[i])) { | ||
| return paths[i] + ' is not a file.'; | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| module.exports = function(extensionDescriptor, fileList) { | ||
| var fileSet = new Set(fileList); | ||
| var error = validateViewBasePath(extensionDescriptor, fileSet, fileList); | ||
| if (error) return error; | ||
| error = validateFileList(extensionDescriptor, fileSet); | ||
| if (error) return error; | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
web-manifest.test.jsandedge-manifest.test.jsdo cover this code, but there are no direct tests verifying:Maybe consider if we need unit tests for these cases.