@znemz/cfn-include 2.1.22 → 2.1.23

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/bin/cli.js CHANGED
@@ -1,23 +1,29 @@
1
1
  #!/usr/bin/env node
2
-
3
- const exec = require('child_process').execSync;
4
- const path = require('path');
5
- const _ = require('lodash');
2
+
3
+ import { execSync } from 'node:child_process';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { readFileSync } from 'node:fs';
7
+ import _ from 'lodash';
6
8
  // path.parse is native in Node.js - no need for path-parse package
7
9
 
8
- const include = require('../index');
9
- const yaml = require('../lib/yaml');
10
- const Client = require('../lib/cfnclient');
11
- const pkg = require('../package.json');
12
- const replaceEnv = require('../lib/replaceEnv');
10
+ import include from '../index.js';
11
+ import * as yaml from '../lib/yaml.js';
12
+ import Client from '../lib/cfnclient.js';
13
+ import replaceEnv from '../lib/replaceEnv.js';
14
+
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = path.dirname(__filename);
17
+
18
+ // Read package.json using fs instead of import assertion
19
+ const pkg = JSON.parse(readFileSync(path.join(__dirname, '../package.json'), 'utf8'));
13
20
 
14
21
  const { env } = process;
15
22
 
16
- (async () => {
17
- const { default : yargs } = await import('yargs');
18
- const { hideBin } = await import('yargs/helpers');
23
+ const { default: yargs } = await import('yargs');
24
+ const { hideBin } = await import('yargs/helpers');
19
25
 
20
- const opts = yargs(hideBin(process.argv))
26
+ const opts = yargs(hideBin(process.argv))
21
27
  .version(false)
22
28
  .command('$0 [path] [options]', pkg.description, (y) =>
23
29
  y.positional('path', {
@@ -60,9 +66,7 @@ const { env } = process;
60
66
  desc: 'bucket name required for templates larger than 50k',
61
67
  },
62
68
  context: {
63
- desc:
64
-
65
- 'template full path. only utilized for stdin when the template is piped to this script',
69
+ desc: 'template full path. only utilized for stdin when the template is piped to this script',
66
70
  required: false,
67
71
  string: true,
68
72
  },
@@ -79,13 +83,11 @@ const { env } = process;
79
83
  inject: {
80
84
  alias: 'i',
81
85
  string: true,
82
-
83
86
  desc: `JSON string payload to use for template injection.`,
84
87
  coerce: (valStr) => JSON.parse(valStr),
85
88
  },
86
89
  doLog: {
87
90
  boolean: true,
88
-
89
91
  desc: `console log out include options in recurse step`,
90
92
  },
91
93
  'ref-now-ignore-missing': {
@@ -111,7 +113,7 @@ const { env } = process;
111
113
  opts.enable = opts.enable.split(',');
112
114
 
113
115
  // Parse ref-now-ignores into an array
114
- const refNowIgnores = opts['ref-now-ignores'] ? opts['ref-now-ignores'].split(',').map(s => s.trim()) : [];
116
+ const refNowIgnores = opts['ref-now-ignores'] ? opts['ref-now-ignores'].split(',').map((s) => s.trim()) : [];
115
117
 
116
118
  let promise;
117
119
  if (opts.path) {
@@ -142,9 +144,7 @@ if (opts.path) {
142
144
  process.exit(1);
143
145
  }
144
146
 
145
- const location = opts.context
146
- ? path.resolve(opts.context)
147
- : path.join(process.cwd(), 'template.yml');
147
+ const location = opts.context ? path.resolve(opts.context) : path.join(process.cwd(), 'template.yml');
148
148
 
149
149
  template = opts.enable.includes('env') ? replaceEnv(template) : template;
150
150
 
@@ -166,13 +166,13 @@ promise
166
166
  if (opts.metadata) {
167
167
  let stdout;
168
168
  try {
169
- stdout = exec('git log -n 1 --pretty=%H', {
169
+ stdout = execSync('git log -n 1 --pretty=%H', {
170
170
  stdio: [0, 'pipe', 'ignore'],
171
171
  })
172
172
  .toString()
173
173
  .trim();
174
174
  } catch {
175
-
175
+ // ignore git errors
176
176
  }
177
177
  _.defaultsDeep(template, {
178
178
  Metadata: {
@@ -194,11 +194,7 @@ promise
194
194
  return template;
195
195
  })
196
196
  .then((template) => {
197
- console.log(
198
- opts.yaml
199
- ? yaml.dump(template, opts)
200
- : JSON.stringify(template, null, opts.minimize ? null : 2),
201
- );
197
+ console.log(opts.yaml ? yaml.dump(template, opts) : JSON.stringify(template, null, opts.minimize ? null : 2));
202
198
  })
203
199
  .catch(function (err) {
204
200
  if (typeof err.toString === 'function') console.error(err.toString());
@@ -206,5 +202,3 @@ promise
206
202
  console.log(err.stack);
207
203
  process.exit(1);
208
204
  });
209
-
210
- })();
package/index.js CHANGED
@@ -1,32 +1,32 @@
1
- const url = require('url');
2
- const path = require('path');
3
- const _ = require('lodash');
4
- const { glob } = require('glob');
5
- const sortObject = require('@znemz/sort-object');
6
- const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
7
- const { addProxyToClient } = require('aws-sdk-v3-proxy');
1
+ import url from 'node:url';
2
+ import path from 'node:path';
3
+ import _ from 'lodash';
4
+ import { glob } from 'glob';
5
+ import sortObject from '@znemz/sort-object';
6
+ import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
7
+ import { addProxyToClient } from 'aws-sdk-v3-proxy';
8
8
 
9
9
  // path.parse is native in Node.js - no need for path-parse package
10
- const deepMerge = require('deepmerge');
11
- const { isTaggableResource } = require('@znemz/cft-utils/src/resources/taggable');
10
+ import deepMerge from 'deepmerge';
11
+ import { isTaggableResource } from '@znemz/cft-utils/src/resources/taggable.js';
12
12
 
13
- const request = require('./lib/request');
14
- const PromiseExt = require('./lib/promise');
13
+ import request from './lib/request.js';
14
+ import * as PromiseExt from './lib/promise.js';
15
15
 
16
16
  const S3 = (opts = {}) => addProxyToClient(new S3Client(opts), { throwOnNoProxy: false });
17
17
 
18
18
  const s3 = S3();
19
- const yaml = require('./lib/yaml');
20
- const { getParser } = require('./lib/include/query');
21
- const parseLocation = require('./lib/parselocation');
22
- const replaceEnv = require('./lib/replaceEnv');
23
-
24
- const { lowerCamelCase, upperCamelCase } = require('./lib/utils');
25
- const { isOurExplicitFunction } = require('./lib/schema');
26
- const { getAwsPseudoParameters, buildResourceArn } = require('./lib/internals');
27
- const { cachedReadFile } = require('./lib/cache');
28
- const { createChildScope } = require('./lib/scope');
29
- const { promiseProps } = require('./lib/promise-utils');
19
+ import * as yaml from './lib/yaml.js';
20
+ import { getParser } from './lib/include/query.js';
21
+ import parseLocation from './lib/parselocation.js';
22
+ import replaceEnv from './lib/replaceEnv.js';
23
+
24
+ import { lowerCamelCase, upperCamelCase } from './lib/utils.js';
25
+ import { isOurExplicitFunction } from './lib/schema.js';
26
+ import { getAwsPseudoParameters, buildResourceArn } from './lib/internals.js';
27
+ import { cachedReadFile } from './lib/cache.js';
28
+ import { createChildScope } from './lib/scope.js';
29
+ import { promiseProps } from './lib/promise-utils.js';
30
30
 
31
31
  /**
32
32
  * @param {object} options
@@ -53,7 +53,7 @@ const { promiseProps } = require('./lib/promise-utils');
53
53
  * doEval: opts.doEval, -- allow Fn::Eval to be used
54
54
  * })
55
55
  */
56
- module.exports = async function (options) {
56
+ export default async function (options) {
57
57
  let { template } = options;
58
58
  options.doEnv = getBoolEnvOpt(options.doEnv, 'CFN_INCLUDE_DO_ENV');
59
59
  options.doEval = getBoolEnvOpt(options.doEval, 'CFN_INCLUDE_DO_EVAL');
@@ -72,7 +72,7 @@ module.exports = async function (options) {
72
72
  rootTemplate: resolvedTemplate,
73
73
  ...options,
74
74
  });
75
- };
75
+ }
76
76
 
77
77
  /**
78
78
  * @param {object} base file options
@@ -310,9 +310,9 @@ async function recurse({ base, scope, cft, rootTemplate, caller, ...opts }) {
310
310
  delete cft['Fn::DeepMerge'];
311
311
  let mergedObj = {};
312
312
  if (json && json.length) {
313
- json.forEach((j) => {
313
+ for (const j of json) {
314
314
  mergedObj = deepMerge(mergedObj, j);
315
- });
315
+ }
316
316
  }
317
317
  return recurse({ base, scope, cft: _.defaults(cft, mergedObj), rootTemplate, caller: 'Fn::DeepMerge', ...opts });
318
318
  },
@@ -616,15 +616,15 @@ function findAndReplace(scope, object) {
616
616
  }
617
617
  }
618
618
  if (Array.isArray(object)) {
619
- object = object.map(_.bind(findAndReplace, this, scope));
619
+ object = object.map((item) => findAndReplace(scope, item));
620
620
  } else if (_.isPlainObject(object)) {
621
621
  object = _.mapKeys(object, function (value, key) {
622
622
  return findAndReplace(scope, key);
623
623
  });
624
- Object.keys(object).forEach(function (key) {
625
- if (key === 'Fn::Map') return;
624
+ for (const key of Object.keys(object)) {
625
+ if (key === 'Fn::Map') continue;
626
626
  object[key] = findAndReplace(scope, object[key]);
627
- });
627
+ }
628
628
  }
629
629
  return object;
630
630
  }
@@ -883,13 +883,14 @@ async function handleIncludeBody({ scope, args, body, absolute }) {
883
883
  function JSONifyString(string) {
884
884
  const lines = [];
885
885
  const split = string.toString().split(/(\r?\n)/);
886
- split.forEach(function (line, idx) {
886
+ for (let idx = 0; idx < split.length; idx++) {
887
+ const line = split[idx];
887
888
  if (idx % 2) {
888
889
  lines[(idx - 1) / 2] = lines[(idx - 1) / 2] + line;
889
890
  } else {
890
891
  lines.push(line);
891
892
  }
892
- });
893
+ }
893
894
  return lines;
894
895
  }
895
896
 
package/lib/cache.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * File content cache to avoid redundant disk I/O.
3
3
  */
4
4
 
5
- const { readFile } = require('fs/promises');
5
+ import { readFile } from 'node:fs/promises';
6
6
 
7
7
  // File content cache to avoid re-reading the same files
8
8
  const fileCache = new Map();
@@ -12,7 +12,7 @@ const fileCache = new Map();
12
12
  * @param {string} absolutePath - Absolute path to the file
13
13
  * @returns {Promise<string>} File content as a string
14
14
  */
15
- async function cachedReadFile(absolutePath) {
15
+ export async function cachedReadFile(absolutePath) {
16
16
  if (fileCache.has(absolutePath)) {
17
17
  return fileCache.get(absolutePath);
18
18
  }
@@ -24,11 +24,6 @@ async function cachedReadFile(absolutePath) {
24
24
  /**
25
25
  * Clear the file cache (useful for testing)
26
26
  */
27
- function clearFileCache() {
27
+ export function clearFileCache() {
28
28
  fileCache.clear();
29
29
  }
30
-
31
- module.exports = {
32
- cachedReadFile,
33
- clearFileCache,
34
- };
package/lib/cfnclient.js CHANGED
@@ -1,12 +1,9 @@
1
- const {
2
- CloudFormationClient,
3
- ValidateTemplateCommand,
4
- } = require('@aws-sdk/client-cloudformation');
5
- const { S3Client, PutObjectCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
6
- const { addProxyToClient } = require('aws-sdk-v3-proxy');
1
+ import { CloudFormationClient, ValidateTemplateCommand } from '@aws-sdk/client-cloudformation';
2
+ import { S3Client, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3';
3
+ import { addProxyToClient } from 'aws-sdk-v3-proxy';
7
4
 
8
- const { posix: path } = require('path');
9
- const crypto = require('crypto');
5
+ import path from 'node:path';
6
+ import crypto from 'node:crypto';
10
7
 
11
8
  const S3 = (opts = {}) => addProxyToClient(new S3Client(opts));
12
9
  const CloudFormation = (opts = {}) => addProxyToClient(new CloudFormationClient(opts));
@@ -29,7 +26,7 @@ class Client {
29
26
  }
30
27
 
31
28
  async uploadTemplate(tpl, callback) {
32
- const key = path.join(this.prefix, `${this.digest(tpl)}.json`);
29
+ const key = path.posix.join(this.prefix, `${this.digest(tpl)}.json`);
33
30
  await this.s3.Send(
34
31
  new PutObjectCommand({
35
32
  Body: tpl,
@@ -84,4 +81,4 @@ class Client {
84
81
  }
85
82
  }
86
83
 
87
- module.exports = Client;
84
+ export default Client;
@@ -1,9 +1,13 @@
1
- let AWS = require('aws-sdk-proxy'),
2
- jmespath = require('jmespath');
1
+ // NOTE: This module uses the legacy AWS SDK v2 via aws-sdk-proxy
2
+ // It may be unused and could be removed or rewritten for SDK v3
3
+ import AWS from 'aws-sdk-proxy';
4
+ import jmespath from 'jmespath';
3
5
 
4
- module.exports = function (args) {
5
- var service = new AWS[args.service](args.region ? { region: args.region } : null);
6
- return service[args.action](args.parameters ? args.parameters : {}).promise().then(function (res) {
7
- return args.query ? jmespath.search(res, args.query) : res;
8
- });
6
+ export default function (args) {
7
+ const service = new AWS[args.service](args.region ? { region: args.region } : null);
8
+ return service[args.action](args.parameters ? args.parameters : {})
9
+ .promise()
10
+ .then(function (res) {
11
+ return args.query ? jmespath.search(res, args.query) : res;
12
+ });
9
13
  }
@@ -1,19 +1,16 @@
1
- const { get } = require("lodash");
2
- const { search } = require("jmespath");
1
+ import _ from 'lodash';
2
+ import jmespath from 'jmespath';
3
3
 
4
4
  // this exists cause in most cases lodash get is plenty sufficient
5
- // also this bug / error in jmespath is rediculous https://github.com/jmespath/jmespath.js/issues/35
5
+ // also this bug / error in jmespath is ridiculous https://github.com/jmespath/jmespath.js/issues/35
6
6
  const queryParsers = {
7
- lodash: (obj, path) => get(obj, path) || "",
8
- jmespath: search,
9
- default: search,
7
+ lodash: (obj, path) => _.get(obj, path) || '',
8
+ jmespath: jmespath.search,
9
+ default: jmespath.search,
10
10
  };
11
11
 
12
- queryParsers["default"] =
13
- queryParsers[process.env.CFN_INCLUDE_QUERY_PARSER] || queryParsers.default;
12
+ queryParsers['default'] = queryParsers[process.env.CFN_INCLUDE_QUERY_PARSER] || queryParsers.default;
14
13
 
15
- function getParser(type) {
14
+ export function getParser(type) {
16
15
  return queryParsers[type] || queryParsers.default;
17
16
  }
18
-
19
- module.exports = { getParser };
package/lib/internals.js CHANGED
@@ -168,7 +168,4 @@ function buildResourceArn(resourceType, properties = {}, pseudoParams = {}, opti
168
168
  return null;
169
169
  }
170
170
 
171
- module.exports = {
172
- getAwsPseudoParameters,
173
- buildResourceArn,
174
- };
171
+ export { getAwsPseudoParameters, buildResourceArn };
@@ -1,17 +1,15 @@
1
- var { isUndefined } = require('lodash');
2
-
3
- module.exports = function parseLocation(location) {
4
- if(!location) return {};
1
+ export default function parseLocation(location) {
2
+ if (!location) return {};
5
3
  if (!location.match) {
6
4
  console.error('location.match is not a function', location);
7
5
  }
8
- var parsed = location.match(/^(((\w+):)?\/\/)?(.*?)([\\\/](.*))?$/);
6
+ const parsed = location.match(/^(((\w+):)?\/\/)?(.*?)([\\\/](.*))?$/);
9
7
 
10
8
  return {
11
9
  protocol: parsed[3],
12
10
  host: parsed[4],
13
11
  path: parsed[5],
14
- relative: isUndefined(parsed[1]),
12
+ relative: parsed[1] === undefined,
15
13
  raw: location,
16
14
  };
17
15
  }
@@ -12,9 +12,9 @@ async function promiseProps(obj) {
12
12
  const keys = Object.keys(obj);
13
13
  const values = await Promise.all(keys.map((key) => obj[key]));
14
14
  const result = {};
15
- keys.forEach((key, i) => {
16
- result[key] = values[i];
17
- });
15
+ for (let i = 0; i < keys.length; i++) {
16
+ result[keys[i]] = values[i];
17
+ }
18
18
  return result;
19
19
  }
20
20
 
@@ -43,8 +43,4 @@ function promiseMap(arr, fn) {
43
43
  return Promise.all(arr.map(fn));
44
44
  }
45
45
 
46
- module.exports = {
47
- promiseProps,
48
- promiseTry,
49
- promiseMap,
50
- };
46
+ export { promiseProps, promiseTry, promiseMap };
package/lib/promise.js CHANGED
@@ -1,4 +1,4 @@
1
- const { promiseTry, promiseMap } = require('./promise-utils');
1
+ import { promiseTry, promiseMap } from './promise-utils.js';
2
2
 
3
3
  /*
4
4
  Maps over objects or iterables just like lodash.
@@ -15,7 +15,4 @@ const mapWhatever = (promises, cb) =>
15
15
  }),
16
16
  );
17
17
 
18
- module.exports = {
19
- mapWhatever,
20
- mapX: mapWhatever,
21
- };
18
+ export { mapWhatever, mapWhatever as mapX };
package/lib/replaceEnv.js CHANGED
@@ -1,5 +1,5 @@
1
- const passThrough = (template) => template
2
- const replaceProcessEnv = (template) => replaceEnv(template, process.env, false)
1
+ const passThrough = (template) => template;
2
+ const replaceProcessEnv = (template) => replaceEnv(template, process.env, false);
3
3
 
4
4
  // Cache for compiled regex patterns to avoid re-creating them
5
5
  const regexCache = new Map();
@@ -29,39 +29,38 @@ function getVarRegex(key, withBraces) {
29
29
  return regexCache.get(cacheKey);
30
30
  }
31
31
 
32
- const replaceEnv = (template, inject = {}, doEnv) => {
32
+ let processTemplate;
33
+
34
+ function replaceEnv(template, inject = {}, doEnv) {
33
35
  processTemplate = doEnv ? replaceProcessEnv : passThrough;
34
36
 
35
- if (!template || typeof template !== "string") {
36
- // return template;
37
- return processTemplate(template)
38
- };
37
+ if (!template || typeof template !== 'string') {
38
+ return processTemplate(template);
39
+ }
39
40
 
40
41
  const keys = Object.keys(inject);
41
42
 
42
43
  for (let i = 0; i < keys.length; i++) {
43
44
  const key = keys[i];
44
- let val = inject[key];
45
+ const val = inject[key];
45
46
 
46
47
  // Use cached regex patterns instead of creating new ones each time
47
48
  const bareRegex = getVarRegex(key, false);
48
49
  const bracedRegex = getVarRegex(key, true);
49
-
50
+
50
51
  // Reset lastIndex for global regex reuse
51
52
  bareRegex.lastIndex = 0;
52
53
  bracedRegex.lastIndex = 0;
53
-
54
- template = template
55
- .replace(bareRegex, val)
56
- .replace(bracedRegex, val);
54
+
55
+ template = template.replace(bareRegex, val).replace(bracedRegex, val);
57
56
  }
58
57
 
59
- // return template;
60
58
  return processTemplate(template);
61
59
  }
62
60
 
63
- const IsRegExVar = (str) => /\$\w+/.test(str) || /\$\{\w+\}/.test(str)
61
+ const IsRegExVar = (str) => /\$\w+/.test(str) || /\$\{\w+\}/.test(str);
64
62
 
65
63
  replaceEnv.IsRegExVar = IsRegExVar; // hack to be backward compat
66
64
 
67
- module.exports = replaceEnv;
65
+ export default replaceEnv;
66
+ export { IsRegExVar };
package/lib/request.js CHANGED
@@ -1,17 +1,22 @@
1
- var url = require('url'),
2
- https = require('https'),
3
- http = require('http');
1
+ import { parse as urlParse } from 'node:url';
2
+ import https from 'node:https';
3
+ import http from 'node:http';
4
4
 
5
- module.exports = function(location) {
6
- var parsed = url.parse(location),
7
- proto = parsed.protocol === 'https:' ? https : http;
8
-
9
- return new Promise((resolve, reject) => proto.get(location, res => {
10
- if (res.statusCode > 299) return reject(new Error('HTTP request failed with status code ' + res.statusCode));
11
- var rawData = [];
12
- res.setEncoding('utf8');
13
- res.on('data', chunk => rawData.push(chunk));
14
- res.on('end', () => resolve(rawData.join('')));
15
- }).on('error', reject));
16
-
17
- }
5
+ export default function request(location) {
6
+ const parsed = urlParse(location);
7
+ const proto = parsed.protocol === 'https:' ? https : http;
8
+
9
+ return new Promise((resolve, reject) =>
10
+ proto
11
+ .get(location, (res) => {
12
+ if (res.statusCode > 299) {
13
+ return reject(new Error('HTTP request failed with status code ' + res.statusCode));
14
+ }
15
+ const rawData = [];
16
+ res.setEncoding('utf8');
17
+ res.on('data', (chunk) => rawData.push(chunk));
18
+ res.on('end', () => resolve(rawData.join('')));
19
+ })
20
+ .on('error', reject),
21
+ );
22
+ }
package/lib/schema.js CHANGED
@@ -1,7 +1,7 @@
1
- var yaml = require('js-yaml'),
2
- _ = require('lodash');
1
+ import yaml from 'js-yaml';
2
+ import _ from 'lodash';
3
3
 
4
- var tags = [
4
+ const tags = [
5
5
  { short: 'Include', full: 'Fn::Include', type: 'scalar' },
6
6
  { short: 'Include', full: 'Fn::Include', type: 'mapping' },
7
7
  { short: 'Stringify', full: 'Fn::Stringify', type: 'sequence' },
@@ -73,8 +73,8 @@ var tags = [
73
73
  kind: fn.type,
74
74
  construct: function (obj) {
75
75
  if (fn.dotSyntax && _.isString(obj)) {
76
- var indexOfDot = obj.indexOf('.');
77
- if (indexOfDot != -1) obj = [obj.substr(0, indexOfDot), obj.substr(indexOfDot + 1)];
76
+ const indexOfDot = obj.indexOf('.');
77
+ if (indexOfDot !== -1) obj = [obj.substr(0, indexOfDot), obj.substr(indexOfDot + 1)];
78
78
  else obj = [obj];
79
79
  }
80
80
  return _.fromPairs([[fn.full, obj]]);
@@ -106,12 +106,12 @@ const BANG_AMAZON_FUNCS = [
106
106
 
107
107
  const EXPLICIT_AMAZON_FUNCS = BANG_AMAZON_FUNCS.map((f) => `Fn::${f}`);
108
108
 
109
- module.exports = yaml.DEFAULT_SCHEMA.extend(tags);
110
-
111
- module.exports.EXPLICIT_AMAZON_FUNCS = EXPLICIT_AMAZON_FUNCS;
112
- module.exports.BANG_AMAZON_FUNCS = BANG_AMAZON_FUNCS;
109
+ const yamlSchema = yaml.DEFAULT_SCHEMA.extend(tags);
113
110
 
114
111
  // Test the function key to make sure it's something
115
112
  // we should process.
116
- module.exports.isOurExplicitFunction = (testKeyForFunc) =>
117
- /Fn::.*/.test(testKeyForFunc) && EXPLICIT_AMAZON_FUNCS.indexOf(testKeyForFunc) === -1;
113
+ const isOurExplicitFunction = (testKeyForFunc) =>
114
+ /Fn::.*/.test(testKeyForFunc) && !EXPLICIT_AMAZON_FUNCS.includes(testKeyForFunc);
115
+
116
+ export default yamlSchema;
117
+ export { EXPLICIT_AMAZON_FUNCS, BANG_AMAZON_FUNCS, isOurExplicitFunction };
package/lib/scope.js CHANGED
@@ -14,7 +14,7 @@
14
14
  * @param {Object} [additions={}] - Properties to add to the child scope
15
15
  * @returns {Object} A new child scope with prototype chain to parent
16
16
  */
17
- function createChildScope(parent, additions = {}) {
17
+ export function createChildScope(parent, additions = {}) {
18
18
  const child = Object.create(parent);
19
19
  Object.assign(child, additions);
20
20
  return child;
@@ -30,7 +30,7 @@ function createChildScope(parent, additions = {}) {
30
30
  * @param {Object} scope - The scope to flatten
31
31
  * @returns {Object} A plain object with all inherited properties
32
32
  */
33
- function scopeToObject(scope) {
33
+ export function scopeToObject(scope) {
34
34
  const result = {};
35
35
  for (const key in scope) {
36
36
  result[key] = scope[key];
@@ -45,14 +45,8 @@ function scopeToObject(scope) {
45
45
  * @param {Object} scope - The scope to iterate over
46
46
  * @param {Function} callback - Function to call with (value, key)
47
47
  */
48
- function forEachInScope(scope, callback) {
48
+ export function forEachInScope(scope, callback) {
49
49
  for (const key in scope) {
50
50
  callback(scope[key], key);
51
51
  }
52
52
  }
53
-
54
- module.exports = {
55
- createChildScope,
56
- scopeToObject,
57
- forEachInScope,
58
- };
package/lib/utils.js CHANGED
@@ -1,11 +1,11 @@
1
- const assert = require('assert').strict;
1
+ import assert from 'node:assert/strict';
2
2
 
3
3
  function upperCamelCase(str) {
4
4
  assert(typeof str === 'string', 'argument to upper/lowerCamelCase must be a string');
5
5
  return str
6
- .split(/[\._-\s]+/)
7
- .map((s) => s.charAt(0).toUpperCase() + s.slice(1).toLowerCase())
8
- .join('');
6
+ .split(/[\._-\s]+/)
7
+ .map((s) => s.charAt(0).toUpperCase() + s.slice(1).toLowerCase())
8
+ .join('');
9
9
  }
10
10
 
11
11
  function lowerCamelCase(str) {
@@ -13,7 +13,4 @@ function lowerCamelCase(str) {
13
13
  return upper.charAt(0).toLowerCase() + upper.slice(1);
14
14
  }
15
15
 
16
- module.exports = {
17
- lowerCamelCase,
18
- upperCamelCase,
19
- };
16
+ export { lowerCamelCase, upperCamelCase };
package/lib/yaml.js CHANGED
@@ -1,22 +1,76 @@
1
- const minify = require('jsonminify');
2
- const yaml = require('js-yaml');
3
- const yamlSchema = require('./schema');
1
+ import yaml from 'js-yaml';
2
+ import yamlSchema from './schema.js';
4
3
 
5
- module.exports = {
6
- load: (res) => {
7
- let json;
8
- try {
9
- json = yaml.load(res, { schema: yamlSchema });
10
- } catch (yamlErr) {
11
- try {
12
- json = JSON.parse(minify(res));
13
- } catch (jsonErr) {
14
- const err = new Error([yamlErr, jsonErr]);
15
- err.name = 'SyntaxError';
16
- throw err;
4
+ /**
5
+ * Simple JSON minify - strips comments and whitespace.
6
+ * Handles JavaScript-style single-line (//) and multi-line comments.
7
+ * @param {string} json - JSON string potentially with comments
8
+ * @returns {string} Minified JSON without comments
9
+ */
10
+ function jsonMinify(json) {
11
+ // Remove single-line comments (// ...)
12
+ // Remove multi-line comments (/* ... */)
13
+ // Be careful not to remove // or /* inside strings
14
+ let inString = false;
15
+ let escaped = false;
16
+ let result = '';
17
+ let i = 0;
18
+
19
+ while (i < json.length) {
20
+ const char = json[i];
21
+ const nextChar = json[i + 1];
22
+
23
+ if (inString) {
24
+ result += char;
25
+ if (escaped) {
26
+ escaped = false;
27
+ } else if (char === '\\') {
28
+ escaped = true;
29
+ } else if (char === '"') {
30
+ inString = false;
31
+ }
32
+ i++;
33
+ } else if (char === '"') {
34
+ inString = true;
35
+ result += char;
36
+ i++;
37
+ } else if (char === '/' && nextChar === '/') {
38
+ // Single-line comment - skip until newline
39
+ while (i < json.length && json[i] !== '\n') {
40
+ i++;
41
+ }
42
+ } else if (char === '/' && nextChar === '*') {
43
+ // Multi-line comment - skip until */
44
+ i += 2;
45
+ while (i < json.length - 1 && !(json[i] === '*' && json[i + 1] === '/')) {
46
+ i++;
17
47
  }
48
+ i += 2; // Skip */
49
+ } else {
50
+ result += char;
51
+ i++;
18
52
  }
19
- return json;
20
- },
21
- dump: (obj, opts) => yaml.dump(obj, { sortKeys: true, ...opts }),
22
- };
53
+ }
54
+
55
+ return result;
56
+ }
57
+
58
+ export function load(res) {
59
+ let json;
60
+ try {
61
+ json = yaml.load(res, { schema: yamlSchema });
62
+ } catch (yamlErr) {
63
+ try {
64
+ json = JSON.parse(jsonMinify(res));
65
+ } catch (jsonErr) {
66
+ const err = new Error([yamlErr, jsonErr]);
67
+ err.name = 'SyntaxError';
68
+ throw err;
69
+ }
70
+ }
71
+ return json;
72
+ }
73
+
74
+ export function dump(obj, opts) {
75
+ return yaml.dump(obj, { sortKeys: true, ...opts });
76
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@znemz/cfn-include",
3
- "version": "2.1.22",
3
+ "version": "2.1.23",
4
4
  "description": "Preprocessor for CloudFormation templates with support for loops and flexible include statements",
5
5
  "keywords": [
6
6
  "aws",
@@ -21,6 +21,11 @@
21
21
  "name": "Nicholas McCready",
22
22
  "email": "nemtcan@gmail.com"
23
23
  },
24
+ "type": "module",
25
+ "exports": {
26
+ ".": "./index.js",
27
+ "./lib/*": "./lib/*"
28
+ },
24
29
  "bin": {
25
30
  "cfn-include": "bin/cli.js"
26
31
  },
@@ -52,7 +57,6 @@
52
57
  "glob": "^13.0.0",
53
58
  "jmespath": "^0.16.0",
54
59
  "js-yaml": "^4.1.1",
55
- "jsonminify": "^0.4.1",
56
60
  "lodash": "^4.17.21",
57
61
  "proxy-agent": "6.5.0",
58
62
  "yargs": "~18.0.0"