magic-comments-loader 2.0.5 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -46,6 +46,7 @@ The `webpackChunkName` comment is added by default when registering the loader.
46
46
  * [`verbose`](#verbose)
47
47
  * [`mode`](#mode)
48
48
  * [`match`](#match)
49
+ * [`comments`](#comments)
49
50
  * `[magicCommentName: string]: MagicCommentValue` see `magic-comments` [options](https://github.com/morganney/magic-comments#options) for details
50
51
 
51
52
  ### `verbose`
@@ -75,6 +76,18 @@ Sets how the loader finds dynamic import expressions in your source code, either
75
76
 
76
77
  Sets how globs are matched, either the module file path, or the `import()` specifier.
77
78
 
79
+ ### `comments`
80
+ **type**
81
+ ```ts
82
+ 'ignore' | 'prepend' | 'append' | 'replace'
83
+ | (cmts: Array<{ start: number; end: number; text: string }>, magicComment: string) => string
84
+ ```
85
+ **default** `'ignore'`
86
+
87
+ _Note, this option only considers block comments that precede the dynamic imports specifier, and any comments coming after are ignored and left intact._
88
+
89
+ Sets how dynamic imports with block comments are handled. If `ignore` is used, then it will be skipped and no magic comments from your configuration will be applied. If `replace` is used, then all found comments will be replaced with the magic comments. `append` and `prepend` add the magic comments before, or after the found comments, respectively. If a function is used it will be passed the found comments, and the magic comment string that is to be applied. The return value has the same effect as `replace`.
90
+
78
91
  ## Examples
79
92
 
80
93
  Below are examples for some of the supported magic comments. Consult the [loader specification](https://github.com/morganney/magic-comments-loader/blob/main/__tests__/loader.spec.js) for a comprehensive usage example.
@@ -10,24 +10,21 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
10
10
  const format = ({
11
11
  match,
12
12
  source,
13
- filepath,
14
13
  comments,
14
+ filepath,
15
+ astComments,
15
16
  magicCommentOptions,
16
17
  importExpressionNodes
17
18
  }) => {
18
19
  const magicImports = [];
19
- const cmts = [...comments];
20
20
  const src = new _magicString.default(source);
21
- const hasComment = node => {
22
- const idx = cmts.findIndex(cmt => cmt.start > node.start && cmt.end < node.end);
23
- const wasFound = idx > -1;
24
- if (wasFound) {
25
- cmts.splice(idx, 1);
26
- }
27
- return wasFound;
21
+ const getComments = node => {
22
+ // This ignores comments that come after the imports specifier.
23
+ return astComments.filter(cmt => cmt.start > node.start && cmt.end < node.end && cmt.start < node.source.end);
28
24
  };
29
25
  for (const node of importExpressionNodes) {
30
- if (!hasComment(node)) {
26
+ const cmts = getComments(node);
27
+ if (!cmts.length || comments !== 'ignore') {
31
28
  const specifier = source.substring(node.source.start, node.source.end);
32
29
  const magicComment = (0, _magicComments.getMagicComment)({
33
30
  match,
@@ -36,8 +33,36 @@ const format = ({
36
33
  options: magicCommentOptions
37
34
  });
38
35
  if (magicComment) {
39
- magicImports.push(src.snip(node.start, node.end).toString().replace(specifier, `${magicComment} ${specifier}`));
40
- src.appendLeft(node.source.start, `${magicComment} `);
36
+ const clone = src.snip(node.start, node.end);
37
+ if (!cmts.length) {
38
+ magicImports.push(clone.toString().replace(specifier, `${magicComment} ${specifier}`));
39
+ src.appendLeft(node.source.start, `${magicComment} `);
40
+ } else {
41
+ /**
42
+ * Get the minimum start and maximum end.
43
+ * Assumption is that comment nodes are sorted
44
+ * in ascending order of `node.start`.
45
+ */
46
+ const minStart = cmts[0].start;
47
+ const maxEnd = cmts[cmts.length - 1].end;
48
+ if (comments === 'replace') {
49
+ magicImports.push(clone.overwrite(minStart, maxEnd, magicComment).toString());
50
+ src.overwrite(minStart, maxEnd, magicComment);
51
+ } else if (comments === 'append') {
52
+ magicImports.push(clone.appendRight(maxEnd, ` ${magicComment}`).toString());
53
+ src.appendRight(maxEnd, ` ${magicComment}`);
54
+ } else if (comments === 'prepend') {
55
+ magicImports.push(clone.prependLeft(minStart, `${magicComment} `).toString());
56
+ src.prependLeft(minStart, `${magicComment} `);
57
+ } else {
58
+ // Has to be a function or the schema validator is broken
59
+ const replacement = comments(cmts, magicComment);
60
+ if (typeof replacement === 'string') {
61
+ magicImports.push(clone.overwrite(minStart, maxEnd, replacement).toString());
62
+ src.overwrite(minStart, maxEnd, replacement);
63
+ }
64
+ }
65
+ }
41
66
  }
42
67
  }
43
68
  }
@@ -20,6 +20,7 @@ const loader = function (source) {
20
20
  const {
21
21
  mode = 'parser',
22
22
  match = 'module',
23
+ comments = 'ignore',
23
24
  verbose = false,
24
25
  ...rest
25
26
  } = options;
@@ -32,6 +33,7 @@ const loader = function (source) {
32
33
  ...(0, _parser.parse)(source),
33
34
  match,
34
35
  filepath,
36
+ comments,
35
37
  magicCommentOptions
36
38
  });
37
39
  if (verbose) {
@@ -21,7 +21,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
21
21
  (0, _acornJsxWalk.extend)(_acornWalk.base);
22
22
  const jsxParser = _acorn.Parser.extend((0, _acornJsx.default)());
23
23
  const parse = source => {
24
- const comments = [];
24
+ const astComments = [];
25
25
  const importExpressionNodes = [];
26
26
  const ast = jsxParser.parse(source, {
27
27
  locations: false,
@@ -30,12 +30,12 @@ const parse = source => {
30
30
  allowAwaitOutsideFunction: true,
31
31
  allowReturnOutsideFunction: true,
32
32
  allowImportExportEverywhere: true,
33
- onComment: (isBlock, commentText, start, end) => {
33
+ onComment: (isBlock, text, start, end) => {
34
34
  if (isBlock) {
35
- comments.push({
35
+ astComments.push({
36
36
  start,
37
37
  end,
38
- commentText
38
+ text
39
39
  });
40
40
  }
41
41
  }
@@ -47,7 +47,7 @@ const parse = source => {
47
47
  });
48
48
  return {
49
49
  ast,
50
- comments,
50
+ astComments,
51
51
  importExpressionNodes,
52
52
  source
53
53
  };
@@ -5,14 +5,29 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.schema = void 0;
7
7
  var _magicComments = require("magic-comments");
8
- const schema = {
8
+ const schema = exports.schema = {
9
9
  type: 'object',
10
10
  properties: {
11
11
  ..._magicComments.schema.properties,
12
12
  mode: {
13
13
  enum: ['parser', 'regexp']
14
+ },
15
+ comments: {
16
+ /**
17
+ * How to apply magic comments when the dynamic import already includes a block-level comment.
18
+ *
19
+ * - ignore: Default. Skip adding magic comments.
20
+ * - replace: Replace the found comment with any applied magic commments.
21
+ * - append: Add any applied magic comments after the comment.
22
+ * - preprend: Add any applied magic comments before the comment.
23
+ * - Function: (cmts: {}[], magicComment: string) => string
24
+ */
25
+ oneOf: [{
26
+ enum: ['ignore', 'replace', 'prepend', 'append']
27
+ }, {
28
+ instanceof: 'Function'
29
+ }]
14
30
  }
15
31
  },
16
32
  additionalProperties: false
17
- };
18
- exports.schema = schema;
33
+ };
package/dist/formatter.js CHANGED
@@ -3,24 +3,21 @@ import MagicString from 'magic-string';
3
3
  const format = ({
4
4
  match,
5
5
  source,
6
- filepath,
7
6
  comments,
7
+ filepath,
8
+ astComments,
8
9
  magicCommentOptions,
9
10
  importExpressionNodes
10
11
  }) => {
11
12
  const magicImports = [];
12
- const cmts = [...comments];
13
13
  const src = new MagicString(source);
14
- const hasComment = node => {
15
- const idx = cmts.findIndex(cmt => cmt.start > node.start && cmt.end < node.end);
16
- const wasFound = idx > -1;
17
- if (wasFound) {
18
- cmts.splice(idx, 1);
19
- }
20
- return wasFound;
14
+ const getComments = node => {
15
+ // This ignores comments that come after the imports specifier.
16
+ return astComments.filter(cmt => cmt.start > node.start && cmt.end < node.end && cmt.start < node.source.end);
21
17
  };
22
18
  for (const node of importExpressionNodes) {
23
- if (!hasComment(node)) {
19
+ const cmts = getComments(node);
20
+ if (!cmts.length || comments !== 'ignore') {
24
21
  const specifier = source.substring(node.source.start, node.source.end);
25
22
  const magicComment = getMagicComment({
26
23
  match,
@@ -29,8 +26,36 @@ const format = ({
29
26
  options: magicCommentOptions
30
27
  });
31
28
  if (magicComment) {
32
- magicImports.push(src.snip(node.start, node.end).toString().replace(specifier, `${magicComment} ${specifier}`));
33
- src.appendLeft(node.source.start, `${magicComment} `);
29
+ const clone = src.snip(node.start, node.end);
30
+ if (!cmts.length) {
31
+ magicImports.push(clone.toString().replace(specifier, `${magicComment} ${specifier}`));
32
+ src.appendLeft(node.source.start, `${magicComment} `);
33
+ } else {
34
+ /**
35
+ * Get the minimum start and maximum end.
36
+ * Assumption is that comment nodes are sorted
37
+ * in ascending order of `node.start`.
38
+ */
39
+ const minStart = cmts[0].start;
40
+ const maxEnd = cmts[cmts.length - 1].end;
41
+ if (comments === 'replace') {
42
+ magicImports.push(clone.overwrite(minStart, maxEnd, magicComment).toString());
43
+ src.overwrite(minStart, maxEnd, magicComment);
44
+ } else if (comments === 'append') {
45
+ magicImports.push(clone.appendRight(maxEnd, ` ${magicComment}`).toString());
46
+ src.appendRight(maxEnd, ` ${magicComment}`);
47
+ } else if (comments === 'prepend') {
48
+ magicImports.push(clone.prependLeft(minStart, `${magicComment} `).toString());
49
+ src.prependLeft(minStart, `${magicComment} `);
50
+ } else {
51
+ // Has to be a function or the schema validator is broken
52
+ const replacement = comments(cmts, magicComment);
53
+ if (typeof replacement === 'string') {
54
+ magicImports.push(clone.overwrite(minStart, maxEnd, replacement).toString());
55
+ src.overwrite(minStart, maxEnd, replacement);
56
+ }
57
+ }
58
+ }
34
59
  }
35
60
  }
36
61
  }
package/dist/loader.js CHANGED
@@ -14,6 +14,7 @@ const loader = function (source) {
14
14
  const {
15
15
  mode = 'parser',
16
16
  match = 'module',
17
+ comments = 'ignore',
17
18
  verbose = false,
18
19
  ...rest
19
20
  } = options;
@@ -26,6 +27,7 @@ const loader = function (source) {
26
27
  ...parse(source),
27
28
  match,
28
29
  filepath,
30
+ comments,
29
31
  magicCommentOptions
30
32
  });
31
33
  if (verbose) {
package/dist/parser.js CHANGED
@@ -15,7 +15,7 @@ import jsx from 'acorn-jsx';
15
15
  extend(base);
16
16
  const jsxParser = Parser.extend(jsx());
17
17
  const parse = source => {
18
- const comments = [];
18
+ const astComments = [];
19
19
  const importExpressionNodes = [];
20
20
  const ast = jsxParser.parse(source, {
21
21
  locations: false,
@@ -24,12 +24,12 @@ const parse = source => {
24
24
  allowAwaitOutsideFunction: true,
25
25
  allowReturnOutsideFunction: true,
26
26
  allowImportExportEverywhere: true,
27
- onComment: (isBlock, commentText, start, end) => {
27
+ onComment: (isBlock, text, start, end) => {
28
28
  if (isBlock) {
29
- comments.push({
29
+ astComments.push({
30
30
  start,
31
31
  end,
32
- commentText
32
+ text
33
33
  });
34
34
  }
35
35
  }
@@ -41,7 +41,7 @@ const parse = source => {
41
41
  });
42
42
  return {
43
43
  ast,
44
- comments,
44
+ astComments,
45
45
  importExpressionNodes,
46
46
  source
47
47
  };
package/dist/schema.js CHANGED
@@ -5,6 +5,22 @@ const schema = {
5
5
  ...magicSchema.properties,
6
6
  mode: {
7
7
  enum: ['parser', 'regexp']
8
+ },
9
+ comments: {
10
+ /**
11
+ * How to apply magic comments when the dynamic import already includes a block-level comment.
12
+ *
13
+ * - ignore: Default. Skip adding magic comments.
14
+ * - replace: Replace the found comment with any applied magic commments.
15
+ * - append: Add any applied magic comments after the comment.
16
+ * - preprend: Add any applied magic comments before the comment.
17
+ * - Function: (cmts: {}[], magicComment: string) => string
18
+ */
19
+ oneOf: [{
20
+ enum: ['ignore', 'replace', 'prepend', 'append']
21
+ }, {
22
+ instanceof: 'Function'
23
+ }]
8
24
  }
9
25
  },
10
26
  additionalProperties: false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magic-comments-loader",
3
- "version": "2.0.5",
3
+ "version": "2.1.0",
4
4
  "description": "Add webpack magic comments to your dynamic imports at build time.",
5
5
  "main": "dist",
6
6
  "type": "module",
@@ -26,7 +26,7 @@
26
26
  "prepack": "npm run build",
27
27
  "build": "babel-dual-package src --out-dir dist",
28
28
  "lint": "eslint . src __tests__ --ext .js,.cjs",
29
- "lint:fix": "npm run lint -- --fix",
29
+ "prettier": "prettier src __tests__ -w",
30
30
  "test:unit": "node --experimental-vm-modules --no-warnings ./node_modules/.bin/jest",
31
31
  "test:spec": "NODE_OPTIONS='--loader=babel-register-esm --no-warnings' BABEL_ENV=test jest -c jest.config.spec.js",
32
32
  "test": "npm run test:unit && npm run test:spec"
@@ -35,8 +35,8 @@
35
35
  "webpack",
36
36
  "magic comments",
37
37
  "loader",
38
- "dynamic",
39
- "import",
38
+ "dynamic import",
39
+ "webpackChunkName",
40
40
  "build",
41
41
  "config"
42
42
  ],
@@ -46,21 +46,18 @@
46
46
  "dist"
47
47
  ],
48
48
  "devDependencies": {
49
- "@babel/cli": "^7.22.5",
50
- "@babel/core": "^7.22.5",
51
- "@babel/eslint-parser": "^7.22.5",
52
- "@babel/preset-env": "^7.22.5",
53
- "babel-dual-package": "^1.0.0-rc.1",
49
+ "@babel/cli": "^7.23.9",
50
+ "@babel/core": "^7.23.9",
51
+ "@babel/eslint-parser": "^7.23.9",
52
+ "@babel/preset-env": "^7.23.9",
53
+ "babel-dual-package": "^1.1.3",
54
54
  "babel-register-esm": "^1.2.4",
55
- "codecov": "^4.0.0-0",
56
55
  "eslint": "^8.42.0",
57
- "eslint-config-prettier": "^8.8.0",
58
56
  "eslint-plugin-jest": "^27.2.1",
59
- "eslint-plugin-prettier": "^4.2.0",
60
- "jest": "^29.5.0",
61
- "jest-light-runner": "^0.5.0",
62
- "memfs": "^4.0.0",
63
- "prettier": "^2.8.8",
57
+ "jest": "^29.7.0",
58
+ "jest-light-runner": "^0.6.0",
59
+ "memfs": "^4.6.0",
60
+ "prettier": "^3.2.4",
64
61
  "webpack": "^5.87.0"
65
62
  },
66
63
  "dependencies": {
@@ -68,9 +65,19 @@
68
65
  "acorn-jsx": "^5.3.2",
69
66
  "acorn-jsx-walk": "^2.0.0",
70
67
  "acorn-walk": "^8.2.0",
71
- "magic-comments": "^2.1.11",
68
+ "magic-comments": "^2.1.12",
72
69
  "magic-string": "^0.30.0",
73
70
  "micromatch": "^4.0.4",
74
- "schema-utils": "^4.1.0"
71
+ "schema-utils": "^4.2.0"
72
+ },
73
+ "prettier": {
74
+ "printWidth": 90,
75
+ "tabWidth": 2,
76
+ "useTabs": false,
77
+ "semi": false,
78
+ "singleQuote": true,
79
+ "trailingComma": "none",
80
+ "bracketSpacing": true,
81
+ "arrowParens": "avoid"
75
82
  }
76
83
  }