@timeax/scaffold 0.1.0 → 0.1.2
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/dist/ast.d.cts +1 -1
- package/dist/ast.d.ts +1 -1
- package/dist/cli.cjs +65 -51
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +63 -50
- package/dist/cli.mjs.map +1 -1
- package/dist/{config-C0067l3c.d.cts → config-DBARTF0g.d.cts} +7 -0
- package/dist/{config-C0067l3c.d.ts → config-DBARTF0g.d.ts} +7 -0
- package/dist/index.cjs +52 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +50 -37
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -8
- package/src/core/apply-structure.ts +14 -0
- package/src/schema/hooks.ts +8 -0
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import readline from 'readline';
|
|
3
|
-
import
|
|
3
|
+
import path5 from 'path';
|
|
4
4
|
import fs8 from 'fs';
|
|
5
5
|
import { Command } from 'commander';
|
|
6
6
|
import os from 'os';
|
|
@@ -8,6 +8,7 @@ import crypto from 'crypto';
|
|
|
8
8
|
import { pathToFileURL } from 'url';
|
|
9
9
|
import { transform } from 'esbuild';
|
|
10
10
|
import { minimatch } from 'minimatch';
|
|
11
|
+
import pluralize from 'pluralize';
|
|
11
12
|
import chokidar from 'chokidar';
|
|
12
13
|
|
|
13
14
|
// src/schema/index.ts
|
|
@@ -120,31 +121,31 @@ function statSafeSync(targetPath) {
|
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
123
|
function toProjectRelativePath(projectRoot, absolutePath) {
|
|
123
|
-
const absRoot =
|
|
124
|
-
const absTarget =
|
|
125
|
-
const rootWithSep = absRoot.endsWith(
|
|
124
|
+
const absRoot = path5.resolve(projectRoot);
|
|
125
|
+
const absTarget = path5.resolve(absolutePath);
|
|
126
|
+
const rootWithSep = absRoot.endsWith(path5.sep) ? absRoot : absRoot + path5.sep;
|
|
126
127
|
if (!absTarget.startsWith(rootWithSep) && absTarget !== absRoot) {
|
|
127
128
|
throw new Error(
|
|
128
129
|
`Path "${absTarget}" is not inside project root "${absRoot}".`
|
|
129
130
|
);
|
|
130
131
|
}
|
|
131
|
-
const rel =
|
|
132
|
+
const rel = path5.relative(absRoot, absTarget);
|
|
132
133
|
return toPosixPath(rel);
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
// src/core/config-loader.ts
|
|
136
137
|
var logger = defaultLogger.child("[config]");
|
|
137
138
|
async function loadScaffoldConfig(cwd, options = {}) {
|
|
138
|
-
const absCwd =
|
|
139
|
-
const initialScaffoldDir = options.scaffoldDir ?
|
|
139
|
+
const absCwd = path5.resolve(cwd);
|
|
140
|
+
const initialScaffoldDir = options.scaffoldDir ? path5.resolve(absCwd, options.scaffoldDir) : path5.join(absCwd, SCAFFOLD_ROOT_DIR);
|
|
140
141
|
const configPath = options.configPath ?? resolveConfigPath(initialScaffoldDir);
|
|
141
142
|
const config = await importConfig(configPath);
|
|
142
143
|
let configRoot = absCwd;
|
|
143
144
|
if (config.root) {
|
|
144
|
-
configRoot =
|
|
145
|
+
configRoot = path5.resolve(absCwd, config.root);
|
|
145
146
|
}
|
|
146
|
-
const scaffoldDir = options.scaffoldDir ?
|
|
147
|
-
const baseRoot = config.base ?
|
|
147
|
+
const scaffoldDir = options.scaffoldDir ? path5.resolve(absCwd, options.scaffoldDir) : path5.join(configRoot, SCAFFOLD_ROOT_DIR);
|
|
148
|
+
const baseRoot = config.base ? path5.resolve(configRoot, config.base) : configRoot;
|
|
148
149
|
logger.debug(
|
|
149
150
|
`Loaded config: configRoot=${configRoot}, baseRoot=${baseRoot}, scaffoldDir=${scaffoldDir}`
|
|
150
151
|
);
|
|
@@ -163,7 +164,7 @@ function resolveConfigPath(scaffoldDir) {
|
|
|
163
164
|
"config.cjs"
|
|
164
165
|
];
|
|
165
166
|
for (const file of candidates) {
|
|
166
|
-
const full =
|
|
167
|
+
const full = path5.join(scaffoldDir, file);
|
|
167
168
|
if (fs8.existsSync(full)) {
|
|
168
169
|
return full;
|
|
169
170
|
}
|
|
@@ -175,7 +176,7 @@ function resolveConfigPath(scaffoldDir) {
|
|
|
175
176
|
);
|
|
176
177
|
}
|
|
177
178
|
async function importConfig(configPath) {
|
|
178
|
-
const ext =
|
|
179
|
+
const ext = path5.extname(configPath).toLowerCase();
|
|
179
180
|
if (ext === ".ts" || ext === ".tsx") {
|
|
180
181
|
return importTsConfig(configPath);
|
|
181
182
|
}
|
|
@@ -187,9 +188,9 @@ async function importTsConfig(configPath) {
|
|
|
187
188
|
const source = fs8.readFileSync(configPath, "utf8");
|
|
188
189
|
const stat = fs8.statSync(configPath);
|
|
189
190
|
const hash = crypto.createHash("sha1").update(configPath).update(String(stat.mtimeMs)).digest("hex");
|
|
190
|
-
const tmpDir =
|
|
191
|
+
const tmpDir = path5.join(os.tmpdir(), "timeax-scaffold-config");
|
|
191
192
|
ensureDirSync(tmpDir);
|
|
192
|
-
const tmpFile =
|
|
193
|
+
const tmpFile = path5.join(tmpDir, `${hash}.mjs`);
|
|
193
194
|
if (!fs8.existsSync(tmpFile)) {
|
|
194
195
|
const result = await transform(source, {
|
|
195
196
|
loader: "ts",
|
|
@@ -783,7 +784,7 @@ function resolveGroupStructure(scaffoldDir, group, config) {
|
|
|
783
784
|
return group.structure;
|
|
784
785
|
}
|
|
785
786
|
const fileName = group.structureFile ?? `${group.name}.txt`;
|
|
786
|
-
const filePath =
|
|
787
|
+
const filePath = path5.join(scaffoldDir, fileName);
|
|
787
788
|
if (!fs8.existsSync(filePath)) {
|
|
788
789
|
throw new Error(
|
|
789
790
|
`@timeax/scaffold: Group "${group.name}" has no structure. Expected file "${fileName}" in "${scaffoldDir}".`
|
|
@@ -799,7 +800,7 @@ function resolveSingleStructure(scaffoldDir, config) {
|
|
|
799
800
|
return config.structure;
|
|
800
801
|
}
|
|
801
802
|
const fileName = config.structureFile ?? "structure.txt";
|
|
802
|
-
const filePath =
|
|
803
|
+
const filePath = path5.join(scaffoldDir, fileName);
|
|
803
804
|
if (!fs8.existsSync(filePath)) {
|
|
804
805
|
throw new Error(
|
|
805
806
|
`@timeax/scaffold: No structure defined. Expected "${fileName}" in "${scaffoldDir}".`
|
|
@@ -821,7 +822,7 @@ var CacheManager = class {
|
|
|
821
822
|
}
|
|
822
823
|
cache = DEFAULT_CACHE;
|
|
823
824
|
get cachePathAbs() {
|
|
824
|
-
return
|
|
825
|
+
return path5.resolve(this.projectRoot, this.cacheFileRelPath);
|
|
825
826
|
}
|
|
826
827
|
load() {
|
|
827
828
|
const cachePath = this.cachePathAbs;
|
|
@@ -845,7 +846,7 @@ var CacheManager = class {
|
|
|
845
846
|
}
|
|
846
847
|
save() {
|
|
847
848
|
const cachePath = this.cachePathAbs;
|
|
848
|
-
const dir =
|
|
849
|
+
const dir = path5.dirname(cachePath);
|
|
849
850
|
ensureDirSync(dir);
|
|
850
851
|
fs8.writeFileSync(cachePath, JSON.stringify(this.cache, null, 2), "utf8");
|
|
851
852
|
}
|
|
@@ -930,9 +931,9 @@ async function applyStructure(opts) {
|
|
|
930
931
|
interactiveDelete
|
|
931
932
|
} = opts;
|
|
932
933
|
const logger6 = opts.logger ?? defaultLogger.child(groupName ? `[apply:${groupName}]` : "[apply]");
|
|
933
|
-
const projectRootAbs =
|
|
934
|
-
const baseDirAbs =
|
|
935
|
-
baseDirAbs.endsWith(
|
|
934
|
+
const projectRootAbs = path5.resolve(projectRoot);
|
|
935
|
+
const baseDirAbs = path5.resolve(baseDir);
|
|
936
|
+
baseDirAbs.endsWith(path5.sep) ? baseDirAbs : baseDirAbs + path5.sep;
|
|
936
937
|
const desiredPaths = /* @__PURE__ */ new Set();
|
|
937
938
|
const threshold = sizePromptThreshold ?? config.sizePromptThreshold ?? 128 * 1024;
|
|
938
939
|
async function walk(entry, inheritedStub) {
|
|
@@ -945,7 +946,7 @@ async function applyStructure(opts) {
|
|
|
945
946
|
}
|
|
946
947
|
async function handleDir(entry, inheritedStub) {
|
|
947
948
|
const relFromBase = entry.path.replace(/^[./]+/, "");
|
|
948
|
-
const absDir =
|
|
949
|
+
const absDir = path5.resolve(baseDirAbs, relFromBase);
|
|
949
950
|
const relFromRoot = toPosixPath(
|
|
950
951
|
toProjectRelativePath(projectRootAbs, absDir)
|
|
951
952
|
);
|
|
@@ -960,24 +961,30 @@ async function applyStructure(opts) {
|
|
|
960
961
|
}
|
|
961
962
|
async function handleFile(entry, inheritedStub) {
|
|
962
963
|
const relFromBase = entry.path.replace(/^[./]+/, "");
|
|
963
|
-
const absFile =
|
|
964
|
+
const absFile = path5.resolve(baseDirAbs, relFromBase);
|
|
964
965
|
const relFromRoot = toPosixPath(
|
|
965
966
|
toProjectRelativePath(projectRootAbs, absFile)
|
|
966
967
|
);
|
|
967
968
|
desiredPaths.add(relFromRoot);
|
|
968
969
|
const stubName = entry.stub ?? inheritedStub;
|
|
970
|
+
const extension = path5.extname(relFromRoot);
|
|
971
|
+
const fileName = path5.basename(relFromRoot, extension);
|
|
969
972
|
const ctx = {
|
|
970
973
|
projectRoot: projectRootAbs,
|
|
971
974
|
targetPath: relFromRoot,
|
|
972
975
|
absolutePath: absFile,
|
|
973
976
|
isDirectory: false,
|
|
977
|
+
fileName,
|
|
978
|
+
dirName: path5.dirname(relFromRoot),
|
|
979
|
+
extension,
|
|
980
|
+
pluralFileName: pluralize.plural(fileName),
|
|
974
981
|
stubName
|
|
975
982
|
};
|
|
976
983
|
if (fs8.existsSync(absFile)) {
|
|
977
984
|
return;
|
|
978
985
|
}
|
|
979
986
|
await hooks.runRegular("preCreateFile", ctx);
|
|
980
|
-
const dir =
|
|
987
|
+
const dir = path5.dirname(absFile);
|
|
981
988
|
ensureDirSync(dir);
|
|
982
989
|
if (stubName) {
|
|
983
990
|
await hooks.runStub("preStub", ctx);
|
|
@@ -1020,7 +1027,7 @@ async function applyStructure(opts) {
|
|
|
1020
1027
|
if (desiredPaths.has(cachedPath)) {
|
|
1021
1028
|
continue;
|
|
1022
1029
|
}
|
|
1023
|
-
const abs =
|
|
1030
|
+
const abs = path5.resolve(projectRoot, cachedPath);
|
|
1024
1031
|
const stats = statSafeSync(abs);
|
|
1025
1032
|
if (!stats) {
|
|
1026
1033
|
cache.delete(cachedPath);
|
|
@@ -1030,11 +1037,17 @@ async function applyStructure(opts) {
|
|
|
1030
1037
|
cache.delete(cachedPath);
|
|
1031
1038
|
continue;
|
|
1032
1039
|
}
|
|
1040
|
+
const extension = path5.extname(abs);
|
|
1041
|
+
const fileName = path5.basename(abs, extension);
|
|
1033
1042
|
const ctx = {
|
|
1034
1043
|
projectRoot,
|
|
1035
1044
|
targetPath: cachedPath,
|
|
1036
1045
|
absolutePath: abs,
|
|
1037
1046
|
isDirectory: false,
|
|
1047
|
+
fileName,
|
|
1048
|
+
dirName: path5.dirname(cachedPath),
|
|
1049
|
+
extension,
|
|
1050
|
+
pluralFileName: pluralize.plural(fileName),
|
|
1038
1051
|
stubName: entry?.createdByStub
|
|
1039
1052
|
};
|
|
1040
1053
|
await hooks.runRegular("preDeleteFile", ctx);
|
|
@@ -1076,12 +1089,12 @@ var DEFAULT_IGNORE = [
|
|
|
1076
1089
|
"coverage/**"
|
|
1077
1090
|
];
|
|
1078
1091
|
function scanDirectoryToStructureText(rootDir, options = {}) {
|
|
1079
|
-
const absRoot =
|
|
1092
|
+
const absRoot = path5.resolve(rootDir);
|
|
1080
1093
|
const lines = [];
|
|
1081
1094
|
const ignorePatterns = options.ignore ?? DEFAULT_IGNORE;
|
|
1082
1095
|
const maxDepth = options.maxDepth ?? Infinity;
|
|
1083
1096
|
function isIgnored(absPath) {
|
|
1084
|
-
const rel = toPosixPath(
|
|
1097
|
+
const rel = toPosixPath(path5.relative(absRoot, absPath));
|
|
1085
1098
|
if (!rel || rel === ".") return false;
|
|
1086
1099
|
return ignorePatterns.some(
|
|
1087
1100
|
(pattern) => minimatch(rel, pattern, { dot: true })
|
|
@@ -1102,7 +1115,7 @@ function scanDirectoryToStructureText(rootDir, options = {}) {
|
|
|
1102
1115
|
});
|
|
1103
1116
|
for (const dirent of dirents) {
|
|
1104
1117
|
const name = dirent.name;
|
|
1105
|
-
const absPath =
|
|
1118
|
+
const absPath = path5.join(currentAbs, name);
|
|
1106
1119
|
if (isIgnored(absPath)) continue;
|
|
1107
1120
|
const indent = " ".repeat(depth);
|
|
1108
1121
|
if (dirent.isDirectory()) {
|
|
@@ -1125,13 +1138,13 @@ async function scanProjectFromConfig(cwd, options = {}) {
|
|
|
1125
1138
|
const onlyGroups = options.groups;
|
|
1126
1139
|
const results = [];
|
|
1127
1140
|
function scanGroup(cfg, group) {
|
|
1128
|
-
const rootAbs =
|
|
1141
|
+
const rootAbs = path5.resolve(projectRoot, group.root);
|
|
1129
1142
|
const text = scanDirectoryToStructureText(rootAbs, {
|
|
1130
1143
|
ignore: ignorePatterns,
|
|
1131
1144
|
maxDepth
|
|
1132
1145
|
});
|
|
1133
1146
|
const structureFileName = group.structureFile ?? `${group.name}.txt`;
|
|
1134
|
-
const structureFilePath =
|
|
1147
|
+
const structureFilePath = path5.join(scaffoldDir, structureFileName);
|
|
1135
1148
|
return {
|
|
1136
1149
|
groupName: group.name,
|
|
1137
1150
|
groupRoot: group.root,
|
|
@@ -1158,7 +1171,7 @@ async function scanProjectFromConfig(cwd, options = {}) {
|
|
|
1158
1171
|
maxDepth
|
|
1159
1172
|
});
|
|
1160
1173
|
const structureFileName = config.structureFile ?? "structure.txt";
|
|
1161
|
-
const structureFilePath =
|
|
1174
|
+
const structureFilePath = path5.join(scaffoldDir, structureFileName);
|
|
1162
1175
|
results.push({
|
|
1163
1176
|
groupName: "default",
|
|
1164
1177
|
groupRoot: ".",
|
|
@@ -1192,8 +1205,8 @@ async function ensureStructureFilesFromConfig(cwd, options = {}) {
|
|
|
1192
1205
|
const seen = /* @__PURE__ */ new Set();
|
|
1193
1206
|
const ensureFile = (fileName) => {
|
|
1194
1207
|
if (!fileName) return;
|
|
1195
|
-
const filePath =
|
|
1196
|
-
const key =
|
|
1208
|
+
const filePath = path5.join(scaffoldDir, fileName);
|
|
1209
|
+
const key = path5.resolve(filePath);
|
|
1197
1210
|
if (seen.has(key)) return;
|
|
1198
1211
|
seen.add(key);
|
|
1199
1212
|
if (fs8.existsSync(filePath)) {
|
|
@@ -1224,16 +1237,16 @@ async function ensureStructureFilesFromConfig(cwd, options = {}) {
|
|
|
1224
1237
|
|
|
1225
1238
|
// src/core/format.ts
|
|
1226
1239
|
function getStructureFilesFromConfig(projectRoot, scaffoldDir, config) {
|
|
1227
|
-
const baseDir =
|
|
1240
|
+
const baseDir = path5.resolve(projectRoot, scaffoldDir || SCAFFOLD_ROOT_DIR);
|
|
1228
1241
|
const files = [];
|
|
1229
1242
|
if (config.groups && config.groups.length > 0) {
|
|
1230
1243
|
for (const group of config.groups) {
|
|
1231
1244
|
const structureFile = group.structureFile && group.structureFile.trim().length ? group.structureFile : `${group.name}.txt`;
|
|
1232
|
-
files.push(
|
|
1245
|
+
files.push(path5.join(baseDir, structureFile));
|
|
1233
1246
|
}
|
|
1234
1247
|
} else {
|
|
1235
1248
|
const structureFile = config.structureFile || "structure.txt";
|
|
1236
|
-
files.push(
|
|
1249
|
+
files.push(path5.join(baseDir, structureFile));
|
|
1237
1250
|
}
|
|
1238
1251
|
return files;
|
|
1239
1252
|
}
|
|
@@ -1275,7 +1288,7 @@ async function runOnce(cwd, options = {}) {
|
|
|
1275
1288
|
const hooks = new HookRunner(config);
|
|
1276
1289
|
if (config.groups && config.groups.length > 0) {
|
|
1277
1290
|
for (const group of config.groups) {
|
|
1278
|
-
const groupRootAbs =
|
|
1291
|
+
const groupRootAbs = path5.resolve(projectRoot, group.root);
|
|
1279
1292
|
const structure = resolveGroupStructure(scaffoldDir, group, config);
|
|
1280
1293
|
const groupLogger = logger6.child(`[group:${group.name}]`);
|
|
1281
1294
|
await applyStructure({
|
|
@@ -1311,7 +1324,7 @@ async function runOnce(cwd, options = {}) {
|
|
|
1311
1324
|
}
|
|
1312
1325
|
function watchScaffold(cwd, options = {}) {
|
|
1313
1326
|
const logger6 = options.logger ?? defaultLogger.child("[watch]");
|
|
1314
|
-
const scaffoldDir = options.scaffoldDir ?
|
|
1327
|
+
const scaffoldDir = options.scaffoldDir ? path5.resolve(cwd, options.scaffoldDir) : path5.resolve(cwd, SCAFFOLD_ROOT_DIR);
|
|
1315
1328
|
const debounceMs = options.debounceMs ?? 150;
|
|
1316
1329
|
logger6.info(`Watching scaffold directory: ${scaffoldDir}`);
|
|
1317
1330
|
let timer;
|
|
@@ -1346,11 +1359,11 @@ function watchScaffold(cwd, options = {}) {
|
|
|
1346
1359
|
timer = setTimeout(run, debounceMs);
|
|
1347
1360
|
}
|
|
1348
1361
|
function isInteresting(filePath) {
|
|
1349
|
-
const rel =
|
|
1362
|
+
const rel = path5.relative(scaffoldDir, filePath);
|
|
1350
1363
|
if (rel.startsWith("..")) return false;
|
|
1351
|
-
const base =
|
|
1364
|
+
const base = path5.basename(filePath).toLowerCase();
|
|
1352
1365
|
if (base.startsWith("config.")) return true;
|
|
1353
|
-
const ext =
|
|
1366
|
+
const ext = path5.extname(base);
|
|
1354
1367
|
return ext === ".txt" || ext === ".tss" || ext === ".stx";
|
|
1355
1368
|
}
|
|
1356
1369
|
const watcher = chokidar.watch(scaffoldDir, {
|
|
@@ -1467,12 +1480,12 @@ var DEFAULT_STRUCTURE_TXT = `# ${SCAFFOLD_ROOT_DIR}/structure.txt
|
|
|
1467
1480
|
`;
|
|
1468
1481
|
async function initScaffold(cwd, options = {}) {
|
|
1469
1482
|
const scaffoldDirRel = options.scaffoldDir ?? SCAFFOLD_ROOT_DIR;
|
|
1470
|
-
const scaffoldDirAbs =
|
|
1483
|
+
const scaffoldDirAbs = path5.resolve(cwd, scaffoldDirRel);
|
|
1471
1484
|
const configFileName = options.configFileName ?? "config.ts";
|
|
1472
1485
|
const structureFileName = options.structureFileName ?? "structure.txt";
|
|
1473
1486
|
ensureDirSync(scaffoldDirAbs);
|
|
1474
|
-
const configPath =
|
|
1475
|
-
const structurePath =
|
|
1487
|
+
const configPath = path5.join(scaffoldDirAbs, configFileName);
|
|
1488
|
+
const structurePath = path5.join(scaffoldDirAbs, structureFileName);
|
|
1476
1489
|
let createdConfig = false;
|
|
1477
1490
|
let createdStructure = false;
|
|
1478
1491
|
if (fs8.existsSync(configPath) && !options.force) {
|
|
@@ -1536,9 +1549,9 @@ function askYesNo(question) {
|
|
|
1536
1549
|
}
|
|
1537
1550
|
async function handleRunCommand(cwd, baseOpts) {
|
|
1538
1551
|
const logger6 = createCliLogger(baseOpts);
|
|
1539
|
-
const configPath = baseOpts.config ?
|
|
1540
|
-
const scaffoldDir = baseOpts.dir ?
|
|
1541
|
-
const resolvedScaffoldDir = scaffoldDir ??
|
|
1552
|
+
const configPath = baseOpts.config ? path5.resolve(cwd, baseOpts.config) : void 0;
|
|
1553
|
+
const scaffoldDir = baseOpts.dir ? path5.resolve(cwd, baseOpts.dir) : void 0;
|
|
1554
|
+
const resolvedScaffoldDir = scaffoldDir ?? path5.resolve(cwd, SCAFFOLD_ROOT_DIR);
|
|
1542
1555
|
logger6.debug(
|
|
1543
1556
|
`Starting scaffold (cwd=${cwd}, config=${configPath ?? "auto"}, dir=${resolvedScaffoldDir}, watch=${baseOpts.watch ? "yes" : "no"})`
|
|
1544
1557
|
);
|
|
@@ -1578,15 +1591,15 @@ async function handleScanCommand(cwd, scanOpts, baseOpts) {
|
|
|
1578
1591
|
});
|
|
1579
1592
|
return;
|
|
1580
1593
|
}
|
|
1581
|
-
const rootDir =
|
|
1594
|
+
const rootDir = path5.resolve(cwd, scanOpts.root ?? ".");
|
|
1582
1595
|
const ignore = scanOpts.ignore ?? [];
|
|
1583
1596
|
logger6.info(`Scanning directory for structure: ${rootDir}`);
|
|
1584
1597
|
const text = scanDirectoryToStructureText(rootDir, {
|
|
1585
1598
|
ignore
|
|
1586
1599
|
});
|
|
1587
1600
|
if (scanOpts.out) {
|
|
1588
|
-
const outPath =
|
|
1589
|
-
const dir =
|
|
1601
|
+
const outPath = path5.resolve(cwd, scanOpts.out);
|
|
1602
|
+
const dir = path5.dirname(outPath);
|
|
1590
1603
|
ensureDirSync(dir);
|
|
1591
1604
|
fs8.writeFileSync(outPath, text, "utf8");
|
|
1592
1605
|
logger6.info(`Wrote structure to ${outPath}`);
|