Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/commands/reset.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const inquirer = require('inquirer');
const path = require('path');
const { glob } = require('glob');
const config = require('../lib/config');
const { discoverComponents } = require('../lib/discover');
const { discoverComponents, toGlobPattern } = require('../lib/discover');
const { getDomain, getComponentTypes } = require('../lib/vnextConfig');
const { getJsonMetadata, findAllJson, detectComponentType } = require('../lib/workflow');
const { publishComponent, reinitializeSystem } = require('../lib/api');
Expand Down Expand Up @@ -93,7 +93,7 @@ async function resetCommand(options) {
}

// Find JSONs in this folder only
const pattern = path.join(dir, '**/*.json');
const pattern = toGlobPattern(dir, '**/*.json');
const files = await glob(pattern, {
ignore: [
'**/.meta/**',
Expand Down
24 changes: 15 additions & 9 deletions src/lib/csx.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ function getCsxLocation(csxPath, projectRoot) {
/**
* Updates ALL CSX codes in a JSON file
* Updates all references with the same location
* Supports encoding types: NAT (native/plain text), B64 (Base64, default)
* Encoding handling: absent/B64 -> Base64 (default), NAT -> native source as
* an escaped JSON string, any other value (e.g. REF) -> left untouched
* @param {string} jsonPath - JSON file path
* @param {string} csxLocation - CSX location path
* @param {string} base64Code - Base64 encoded CSX content
Expand Down Expand Up @@ -122,17 +123,22 @@ async function updateCodeInJson(jsonPath, csxLocation, base64Code, nativeCode) {
}

if (obj.location === csxLocation && 'code' in obj) {
// Check encoding type: NAT = Native (plain text), B64 or empty = Base64 (default)
// Encoding decides how the CSX content is embedded:
// absent / B64 -> Base64 (default)
// NAT -> JSON-stringified native source
// anything else (e.g. REF) -> leave untouched
const encoding = obj.encoding ? obj.encoding.toUpperCase() : 'B64';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If obj.encoding is not a string (for example, if it is a boolean, number, or null), calling .toUpperCase() directly will throw a TypeError and crash the process.\n\nTo prevent runtime crashes when processing unexpected JSON structures, we should defensively check that obj.encoding is a non-empty string before calling string methods on it.

Suggested change
const encoding = obj.encoding ? obj.encoding.toUpperCase() : 'B64';
const encoding = typeof obj.encoding === 'string' && obj.encoding.trim() ? obj.encoding.trim().toUpperCase() : 'B64';


if (encoding === 'NAT') {
// Native encoding - write plain text content
obj.code = nativeCode;
} else {
// B64 or default - write Base64 encoded content

if (encoding === 'B64') {
obj.code = base64Code;
updateCount++;
} else if (encoding === 'NAT') {
// Native source as-is; JSON.stringify of the whole document escapes
// newlines/quotes so the stored value becomes a normal JSON string.
obj.code = nativeCode;
updateCount++;
}
updateCount++;
// Other encodings (e.g. REF) are intentionally skipped — no modification.
}

// Scan all elements in array or object
Expand Down
20 changes: 17 additions & 3 deletions src/lib/discover.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ const path = require('path');
const fs = require('fs');
const { getComponentsRoot, getComponentTypes } = require('./vnextConfig');

/**
* Builds a glob pattern with forward slashes.
* glob treats backslashes as escape characters, so on Windows a pattern built
* with path.join (which uses "\") breaks "**" recursion and nested files are
* never matched. Always feed glob forward-slash separators.
* @param {string} dir - Base directory
* @param {string} suffix - Glob suffix, e.g. "**\/*.json"
* @returns {string} Forward-slash glob pattern
*/
function toGlobPattern(dir, suffix) {
Comment on lines +12 to +15

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Normalize backslashes in suffix as well, not just path.sep from path.join.

The example suffix ("**\/*.json") contains backslashes, but toGlobPattern only normalizes path.sep from path.join(dir, suffix). On POSIX, path.sep is /, so any "\\" in suffix stay unmodified and may break globbing. Consider also replacing all backslashes with forward slashes (either in suffix before path.join or on the final string) so Windows-style separators in suffix are handled correctly on all platforms.

Suggested implementation:

 * @param {string} suffix - Glob suffix, e.g. "**/*.json"
function toGlobPattern(dir, suffix) {
  // Normalize all path separators (including any backslashes in `suffix`) to forward slashes
  return path.join(dir, suffix).replace(/\\/g, '/');
}

return path.join(dir, suffix).split(path.sep).join('/');
}

/**
* Discovers component folders based on vnext.config.json paths
* Only scans folders defined in paths, ignores everything else
Expand Down Expand Up @@ -35,8 +48,8 @@ async function discoverComponents(projectRoot) {
* @returns {Promise<string[]>} JSON file paths
*/
async function findJsonInComponent(componentDir) {
const pattern = path.join(componentDir, '**/*.json');
const pattern = toGlobPattern(componentDir, '**/*.json');

const files = await glob(pattern, {
ignore: [
'**/.meta/**',
Expand Down Expand Up @@ -90,7 +103,7 @@ async function findAllCsxInComponents(projectRoot) {
// Only scan folders that were discovered from paths
for (const [type, componentDir] of Object.entries(discovered)) {
if (componentDir) {
const pattern = path.join(componentDir, '**/*.csx');
const pattern = toGlobPattern(componentDir, '**/*.csx');
const files = await glob(pattern, {
ignore: [
'**/.meta/**',
Expand Down Expand Up @@ -157,6 +170,7 @@ function detectComponentTypeFromPath(filePath, componentTypes) {
}

module.exports = {
toGlobPattern,
discoverComponents,
findJsonInComponent,
findAllJsonFiles,
Expand Down
4 changes: 2 additions & 2 deletions src/lib/workflow.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { glob } = require('glob');
const { publishComponent } = require('./api');
const { getInstanceId, deleteWorkflow } = require('./db');
const { getComponentTypes } = require('./vnextConfig');
const { discoverComponents, findJsonInComponent } = require('./discover');
const { discoverComponents, findJsonInComponent, toGlobPattern } = require('./discover');

/**
* Gets key and version values from JSON file
Expand Down Expand Up @@ -167,7 +167,7 @@ async function getGitChangedJson(projectRoot) {
* @returns {Promise<string[]>} JSON file paths
*/
async function findAllJsonInComponent(componentDir) {
const pattern = path.join(componentDir, '**/*.json');
const pattern = toGlobPattern(componentDir, '**/*.json');
const files = await glob(pattern, {
ignore: [
'**/.meta/**',
Expand Down
Loading