@heroiclands/package-build 0.4.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @heroiclands/package-build
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 905254d: **`text.mjs` is deleted; the one implementation lives with the diagnostics
8
+ contract it serves.**
9
+
10
+ `locateInText` and `positionOf` computed which line and column a substring sits
11
+ on. `@heroiclands/content-build` computes the same thing in
12
+ `engine/diagnostics.mjs` as `positionOfLiteral`, and has said so in a comment
13
+ for some time:
14
+
15
+ > That is a duplicate worth naming: unlike the diagnostic _format_ or a
16
+ > validation _rule_, "which line and column is this substring on" has exactly
17
+ > one correct answer and cannot drift into disagreement. The tidier arrangement
18
+ > is for that package to re-export this one — the dependency runs that way — and
19
+ > it should, next time either is touched.
20
+
21
+ This is that time. Rather than re-export, the module is removed outright: the
22
+ `./text` subpath was a library surface with one internal caller (`lang.mjs`) and
23
+ one external one, and this package's job is a command line, not a text-utility
24
+ grab bag.
25
+
26
+ **Breaking for anyone importing `@heroiclands/package-build/text`.** Import
27
+ `positionOfLiteral` from `@heroiclands/content-build/engine/diagnostics`
28
+ instead; it is the same arithmetic, and returns `{}` rather than `undefined`
29
+ when the literal is absent — the shape the diagnostics contract already spreads.
30
+ `locateInText` had no callers anywhere and is simply gone.
31
+
3
32
  ## 0.4.0
4
33
 
5
34
  ### Minor Changes
package/index.mjs CHANGED
@@ -56,6 +56,3 @@ export * as deploy from "./deploy.mjs";
56
56
 
57
57
  /** Localization files: what a shippable `lang/*.json` must satisfy. */
58
58
  export * as lang from "./lang.mjs";
59
-
60
- /** Locating a literal inside an arbitrary text file, for positioned findings. */
61
- export * as text from "./text.mjs";
package/lang.mjs CHANGED
@@ -45,7 +45,7 @@
45
45
  * @module
46
46
  */
47
47
 
48
- import { positionOf } from "./text.mjs";
48
+ import { positionOfLiteral } from "@heroiclands/content-build/engine/diagnostics";
49
49
 
50
50
  /**
51
51
  * A single finding, in the fields the shared diagnostic format takes.
@@ -140,7 +140,7 @@ export function validateLangSource(raw) {
140
140
  * @param {string} key - The localization key.
141
141
  * @returns {{line?: number, column?: number}} Spreadable position fields.
142
142
  */
143
- const at = (key) => positionOf(raw, `"${key}"`);
143
+ const at = (key) => positionOfLiteral(raw, `"${key}"`);
144
144
 
145
145
  for (const [key, value] of Object.entries(json)) {
146
146
  if (typeof value !== "string") continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heroiclands/package-build",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package \u2014 manifest, localization, staging, bundle, release and deployment.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
@@ -35,10 +35,6 @@
35
35
  "types": "./types/stage.d.mts",
36
36
  "import": "./stage.mjs"
37
37
  },
38
- "./text": {
39
- "types": "./types/text.d.mts",
40
- "import": "./text.mjs"
41
- },
42
38
  "./package.json": "./package.json",
43
39
  "./config": {
44
40
  "types": "./types/config.d.mts",
@@ -53,7 +49,6 @@
53
49
  "manifest.mjs",
54
50
  "release.mjs",
55
51
  "stage.mjs",
56
- "text.mjs",
57
52
  "types",
58
53
  "CHANGELOG.md",
59
54
  "README.md",
package/types/index.d.mts CHANGED
@@ -4,4 +4,3 @@ export * as stage from "./stage.mjs";
4
4
  export * as release from "./release.mjs";
5
5
  export * as deploy from "./deploy.mjs";
6
6
  export * as lang from "./lang.mjs";
7
- export * as text from "./text.mjs";
package/text.mjs DELETED
@@ -1,74 +0,0 @@
1
- /*
2
- * This file is part of the Song of Heroic Lands (SoHL) system for Foundry VTT.
3
- * Copyright (c) 2024-2026 Tom Rodriguez ("Toasty") — <toasty@heroiclands.org>
4
- *
5
- * This work is licensed under the GNU General Public License v3.0 (GPLv3).
6
- * You may copy, modify, and distribute it under the terms of that license.
7
- *
8
- * For full terms, see the LICENSE.md file in the project root or visit:
9
- * https://www.gnu.org/licenses/gpl-3.0.html
10
- *
11
- * SPDX-License-Identifier: GPL-3.0-or-later
12
- */
13
-
14
- /**
15
- * Locating a literal inside an arbitrary text file.
16
- *
17
- * A build check reports a **finding**, and a finding is only actionable if it
18
- * says where it is (#1668). Most findings are *about* a string the check
19
- * matched — a key, a marker, a caption — so its position is one string search
20
- * away, and making that search is the difference between a finding that can be
21
- * opened and one that has to be hunted for.
22
- *
23
- * `@heroiclands/content-build` owns the diagnostic **format**, and its
24
- * `positionInBody` maps an offset within a parsed content note back to its
25
- * file. That is a different job: the checks here read localization files,
26
- * manifests, source and bundles — none of which are notes. So this module
27
- * carries the generic operation, and nothing carries it twice.
28
- *
29
- * Plain ESM with no filesystem access, so it is unit-testable.
30
- *
31
- * @module
32
- */
33
-
34
- /**
35
- * Where a literal sits in a text.
36
- *
37
- * @param {string} text - The file's contents.
38
- * @param {string} needle - The literal to locate.
39
- * @param {number} [occurrence] - Which occurrence, 1-based. Repeats of the same
40
- * literal are otherwise indistinguishable, which is the symptom the
41
- * diagnostic format exists to remove.
42
- * @returns {{line: number, column: number}|undefined} 1-based position, or
43
- * `undefined` when the literal is not there. A caller that gets `undefined`
44
- * reports the file alone rather than a position that is not the problem.
45
- */
46
- export function locateInText(text, needle, occurrence = 1) {
47
- if (typeof text !== "string" || !needle) return undefined;
48
- let at = -1;
49
- for (let n = 0; n < occurrence; n++) {
50
- at = text.indexOf(needle, at + 1);
51
- if (at === -1) return undefined;
52
- }
53
- const before = text.slice(0, at);
54
- return {
55
- line: before.split("\n").length,
56
- column: at - before.lastIndexOf("\n"),
57
- };
58
- }
59
-
60
- /**
61
- * Where a literal sits, as spreadable diagnostic fields.
62
- *
63
- * Keeps the drop-rather-than-guess rule in one place: an unfound literal
64
- * contributes no position at all, rather than `undefined` fields that read as a
65
- * bug or a `1:1` that sends the reader to the top of the file.
66
- *
67
- * @param {string} text - The file's contents.
68
- * @param {string} needle - The literal to locate.
69
- * @param {number} [occurrence] - Which occurrence, 1-based.
70
- * @returns {{line?: number, column?: number}} Spreadable position fields.
71
- */
72
- export function positionOf(text, needle, occurrence = 1) {
73
- return locateInText(text, needle, occurrence) ?? {};
74
- }
package/types/text.d.mts DELETED
@@ -1,51 +0,0 @@
1
- /**
2
- * Locating a literal inside an arbitrary text file.
3
- *
4
- * A build check reports a **finding**, and a finding is only actionable if it
5
- * says where it is (#1668). Most findings are *about* a string the check
6
- * matched — a key, a marker, a caption — so its position is one string search
7
- * away, and making that search is the difference between a finding that can be
8
- * opened and one that has to be hunted for.
9
- *
10
- * `@heroiclands/content-build` owns the diagnostic **format**, and its
11
- * `positionInBody` maps an offset within a parsed content note back to its
12
- * file. That is a different job: the checks here read localization files,
13
- * manifests, source and bundles — none of which are notes. So this module
14
- * carries the generic operation, and nothing carries it twice.
15
- *
16
- * Plain ESM with no filesystem access, so it is unit-testable.
17
- *
18
- * @module
19
- */
20
- /**
21
- * Where a literal sits in a text.
22
- *
23
- * @param {string} text - The file's contents.
24
- * @param {string} needle - The literal to locate.
25
- * @param {number} [occurrence] - Which occurrence, 1-based. Repeats of the same
26
- * literal are otherwise indistinguishable, which is the symptom the
27
- * diagnostic format exists to remove.
28
- * @returns {{line: number, column: number}|undefined} 1-based position, or
29
- * `undefined` when the literal is not there. A caller that gets `undefined`
30
- * reports the file alone rather than a position that is not the problem.
31
- */
32
- export function locateInText(text: string, needle: string, occurrence?: number): {
33
- line: number;
34
- column: number;
35
- } | undefined;
36
- /**
37
- * Where a literal sits, as spreadable diagnostic fields.
38
- *
39
- * Keeps the drop-rather-than-guess rule in one place: an unfound literal
40
- * contributes no position at all, rather than `undefined` fields that read as a
41
- * bug or a `1:1` that sends the reader to the top of the file.
42
- *
43
- * @param {string} text - The file's contents.
44
- * @param {string} needle - The literal to locate.
45
- * @param {number} [occurrence] - Which occurrence, 1-based.
46
- * @returns {{line?: number, column?: number}} Spreadable position fields.
47
- */
48
- export function positionOf(text: string, needle: string, occurrence?: number): {
49
- line?: number;
50
- column?: number;
51
- };