jsrepo 1.5.0 → 1.6.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/dist/index.js +167 -63
- package/package.json +1 -1
- package/src/commands/build.ts +99 -15
- package/src/utils/build.ts +78 -16
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import fs12 from "node:fs";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { program as
|
|
4
|
+
import { program as program8 } from "commander";
|
|
5
5
|
import path12 from "pathe";
|
|
6
6
|
|
|
7
7
|
// src/commands/add.ts
|
|
@@ -913,7 +913,7 @@ var categorySchema = v2.object({
|
|
|
913
913
|
});
|
|
914
914
|
var TEST_SUFFIXES = [".test.ts", "_test.ts", ".test.js", "_test.js"];
|
|
915
915
|
var isTestFile = (file) => TEST_SUFFIXES.find((suffix) => file.endsWith(suffix)) !== void 0;
|
|
916
|
-
var buildBlocksDirectory = (blocksPath, { cwd, excludeDeps }) => {
|
|
916
|
+
var buildBlocksDirectory = (blocksPath, { cwd, excludeDeps, includeBlocks, includeCategories, errorOnWarn }) => {
|
|
917
917
|
let paths;
|
|
918
918
|
try {
|
|
919
919
|
paths = fs3.readdirSync(blocksPath);
|
|
@@ -925,6 +925,8 @@ var buildBlocksDirectory = (blocksPath, { cwd, excludeDeps }) => {
|
|
|
925
925
|
const categoryDir = path3.join(blocksPath, categoryPath);
|
|
926
926
|
if (fs3.statSync(categoryDir).isFile()) continue;
|
|
927
927
|
const categoryName = path3.basename(categoryPath);
|
|
928
|
+
if (includeCategories.length > 0 && includeCategories.find((val) => val.trim() === categoryName.trim()) === void 0)
|
|
929
|
+
continue;
|
|
928
930
|
const category = {
|
|
929
931
|
name: categoryName,
|
|
930
932
|
blocks: []
|
|
@@ -934,16 +936,29 @@ var buildBlocksDirectory = (blocksPath, { cwd, excludeDeps }) => {
|
|
|
934
936
|
const blockDir = path3.join(categoryDir, file);
|
|
935
937
|
if (fs3.statSync(blockDir).isFile()) {
|
|
936
938
|
if (isTestFile(file)) continue;
|
|
939
|
+
const name2 = path3.parse(path3.basename(file)).name;
|
|
940
|
+
if (includeBlocks.length > 0 && includeBlocks.find((val) => val.trim() === name2.trim()) === void 0)
|
|
941
|
+
continue;
|
|
937
942
|
const lang = languages.find((resolver) => resolver.matches(file));
|
|
938
943
|
if (!lang) {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
+
const error = "files are not currently supported!";
|
|
945
|
+
if (errorOnWarn) {
|
|
946
|
+
program.error(
|
|
947
|
+
color3.red(
|
|
948
|
+
`Couldn't add \`${color3.bold(blockDir)}\` \`*${color3.bold(
|
|
949
|
+
path3.parse(file).ext
|
|
950
|
+
)}\` ${error}`
|
|
951
|
+
)
|
|
952
|
+
);
|
|
953
|
+
} else {
|
|
954
|
+
console.warn(
|
|
955
|
+
`${VERTICAL_LINE} ${WARN} Skipped \`${color3.bold(blockDir)}\` \`*${color3.bold(
|
|
956
|
+
path3.parse(file).ext
|
|
957
|
+
)}\` ${error}`
|
|
958
|
+
);
|
|
959
|
+
}
|
|
944
960
|
continue;
|
|
945
961
|
}
|
|
946
|
-
const name2 = path3.parse(path3.basename(file)).name;
|
|
947
962
|
const testsPath = files.find(
|
|
948
963
|
(f) => TEST_SUFFIXES.find((suffix) => f === `${name2}${suffix}`)
|
|
949
964
|
);
|
|
@@ -975,6 +990,8 @@ var buildBlocksDirectory = (blocksPath, { cwd, excludeDeps }) => {
|
|
|
975
990
|
category.blocks.push(block);
|
|
976
991
|
} else {
|
|
977
992
|
const blockName = file;
|
|
993
|
+
if (includeBlocks.length > 0 && includeBlocks.find((val) => val.trim() === blockName.trim()) === void 0)
|
|
994
|
+
continue;
|
|
978
995
|
const blockFiles = fs3.readdirSync(blockDir);
|
|
979
996
|
const hasTests = blockFiles.findIndex((f) => isTestFile(f)) !== -1;
|
|
980
997
|
const localDepsSet = /* @__PURE__ */ new Set();
|
|
@@ -983,18 +1000,38 @@ var buildBlocksDirectory = (blocksPath, { cwd, excludeDeps }) => {
|
|
|
983
1000
|
for (const f of blockFiles) {
|
|
984
1001
|
if (isTestFile(f)) continue;
|
|
985
1002
|
if (fs3.statSync(path3.join(blockDir, f)).isDirectory()) {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1003
|
+
const error = "subdirectories are not currently supported!";
|
|
1004
|
+
if (errorOnWarn) {
|
|
1005
|
+
program.error(
|
|
1006
|
+
color3.red(
|
|
1007
|
+
`Couldn't add \`${color3.bold(path3.join(blockDir, f))}\` ${error}`
|
|
1008
|
+
)
|
|
1009
|
+
);
|
|
1010
|
+
} else {
|
|
1011
|
+
console.warn(
|
|
1012
|
+
`${VERTICAL_LINE} ${WARN} Skipped \`${color3.bold(path3.join(blockDir, f))}\` ${error}`
|
|
1013
|
+
);
|
|
1014
|
+
}
|
|
989
1015
|
continue;
|
|
990
1016
|
}
|
|
991
1017
|
const lang = languages.find((resolver) => resolver.matches(f));
|
|
992
1018
|
if (!lang) {
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1019
|
+
const error = "files are not currently supported!";
|
|
1020
|
+
if (errorOnWarn) {
|
|
1021
|
+
program.error(
|
|
1022
|
+
color3.red(
|
|
1023
|
+
`Couldn't add \`${color3.bold(path3.join(blockDir, f))}\` \`*${color3.bold(
|
|
1024
|
+
path3.parse(f).ext
|
|
1025
|
+
)}\` ${error}`
|
|
1026
|
+
)
|
|
1027
|
+
);
|
|
1028
|
+
} else {
|
|
1029
|
+
console.warn(
|
|
1030
|
+
`${VERTICAL_LINE} ${WARN} Skipped \`${path3.join(blockDir, f)}\` \`*${color3.bold(
|
|
1031
|
+
path3.parse(f).ext
|
|
1032
|
+
)}\` ${error}`
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
998
1035
|
continue;
|
|
999
1036
|
}
|
|
1000
1037
|
const { local, dependencies, devDependencies } = lang.resolveDependencies({
|
|
@@ -1631,17 +1668,28 @@ ${content}`;
|
|
|
1631
1668
|
import fs7 from "node:fs";
|
|
1632
1669
|
import { outro as outro2, spinner as spinner3 } from "@clack/prompts";
|
|
1633
1670
|
import color8 from "chalk";
|
|
1634
|
-
import { Command as Command2 } from "commander";
|
|
1671
|
+
import { Command as Command2, program as program3 } from "commander";
|
|
1635
1672
|
import path7 from "pathe";
|
|
1636
1673
|
import * as v6 from "valibot";
|
|
1637
1674
|
var schema3 = v6.object({
|
|
1638
1675
|
dirs: v6.array(v6.string()),
|
|
1676
|
+
includeBlocks: v6.array(v6.string()),
|
|
1677
|
+
includeCategories: v6.array(v6.string()),
|
|
1639
1678
|
excludeDeps: v6.array(v6.string()),
|
|
1640
1679
|
output: v6.boolean(),
|
|
1680
|
+
errorOnWarn: v6.boolean(),
|
|
1641
1681
|
verbose: v6.boolean(),
|
|
1642
1682
|
cwd: v6.string()
|
|
1643
1683
|
});
|
|
1644
|
-
var build = new Command2("build").description(`Builds the provided --dirs in the project root into a \`${OUTPUT_FILE}\` file.`).option("--dirs [dirs...]", "The directories containing the blocks.", ["./blocks"]).option("--
|
|
1684
|
+
var build = new Command2("build").description(`Builds the provided --dirs in the project root into a \`${OUTPUT_FILE}\` file.`).option("--dirs [dirs...]", "The directories containing the blocks.", ["./blocks"]).option("--include-blocks [blockNames...]", "Include only the blocks with these names.", []).option(
|
|
1685
|
+
"--include-categories [categoryNames...]",
|
|
1686
|
+
"Include only the categories with these names.",
|
|
1687
|
+
[]
|
|
1688
|
+
).option("--exclude-deps [deps...]", "Dependencies that should not be added.", []).option("--no-output", `Do not output a \`${OUTPUT_FILE}\` file.`).option(
|
|
1689
|
+
"--error-on-warn",
|
|
1690
|
+
"If there is a warning throw an error and do not allow build to complete.",
|
|
1691
|
+
false
|
|
1692
|
+
).option("--verbose", "Include debug logs.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (opts) => {
|
|
1645
1693
|
const options = v6.parse(schema3, opts);
|
|
1646
1694
|
_intro(context.package.version);
|
|
1647
1695
|
await _build(options);
|
|
@@ -1655,25 +1703,81 @@ var _build = async (options) => {
|
|
|
1655
1703
|
const dirPath = path7.join(options.cwd, dir);
|
|
1656
1704
|
loading.start(`Building ${color8.cyan(dirPath)}`);
|
|
1657
1705
|
if (options.output && fs7.existsSync(outFile)) fs7.rmSync(outFile);
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1706
|
+
const builtCategories = buildBlocksDirectory(dirPath, { ...options });
|
|
1707
|
+
for (const category of builtCategories) {
|
|
1708
|
+
if (categories.find((cat) => cat.name === category.name) !== void 0) {
|
|
1709
|
+
const error = "a category with the same name already exists!";
|
|
1710
|
+
if (options.errorOnWarn) {
|
|
1711
|
+
program3.error(
|
|
1712
|
+
color8.red(
|
|
1713
|
+
`\`${color8.bold(`${dir}/${category.name}`)}\` could not be added because ${error}`
|
|
1714
|
+
)
|
|
1715
|
+
);
|
|
1716
|
+
} else {
|
|
1717
|
+
console.warn(
|
|
1718
|
+
`${VERTICAL_LINE} ${WARN} Skipped adding \`${color8.cyan(`${dir}/${category.name}`)}\` because ${error}`
|
|
1719
|
+
);
|
|
1720
|
+
}
|
|
1721
|
+
continue;
|
|
1722
|
+
}
|
|
1723
|
+
categories.push(category);
|
|
1724
|
+
}
|
|
1661
1725
|
loading.stop(`Built ${color8.cyan(dirPath)}`);
|
|
1662
1726
|
}
|
|
1663
|
-
|
|
1727
|
+
loading.start("Checking manifest");
|
|
1728
|
+
const warnings = [];
|
|
1664
1729
|
for (const category of categories) {
|
|
1665
|
-
const
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1730
|
+
for (const block of category.blocks) {
|
|
1731
|
+
for (const dep of block.localDependencies) {
|
|
1732
|
+
const [depCategoryName, depBlockName] = dep.split("/");
|
|
1733
|
+
const depCategory = categories.find(
|
|
1734
|
+
(cat) => cat.name.trim() === depCategoryName.trim()
|
|
1735
|
+
);
|
|
1736
|
+
const invalidDependencyError = () => {
|
|
1737
|
+
const error = `depends on ${color8.bold(dep)} which doesn't exist!`;
|
|
1738
|
+
if (options.errorOnWarn) {
|
|
1739
|
+
warnings.push(
|
|
1740
|
+
color8.red(`${color8.bold(`${category.name}/${block.name}`)} ${error}`)
|
|
1741
|
+
);
|
|
1742
|
+
} else {
|
|
1743
|
+
warnings.push(
|
|
1744
|
+
`${VERTICAL_LINE} ${WARN} ${color8.bold(`${category.name}/${block.name}`)} ${error}`
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1747
|
+
};
|
|
1748
|
+
if (!depCategory) {
|
|
1749
|
+
invalidDependencyError();
|
|
1750
|
+
continue;
|
|
1751
|
+
}
|
|
1752
|
+
if (depCategory.blocks.find((b) => b.name === depBlockName) === void 0) {
|
|
1753
|
+
invalidDependencyError();
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
for (const dep of [...block.dependencies, ...block.devDependencies]) {
|
|
1757
|
+
if (!dep.includes("@")) {
|
|
1758
|
+
const error = `You haven't installed ${color8.bold(dep)} as a dependency so your users could get any version of it when they install your block!`;
|
|
1759
|
+
if (options.errorOnWarn) {
|
|
1760
|
+
warnings.push(color8.red(error));
|
|
1761
|
+
} else {
|
|
1762
|
+
warnings.push(`${VERTICAL_LINE} ${WARN} ${error}`);
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
loading.stop("Completed checking manifest.");
|
|
1769
|
+
if (warnings.length > 0) {
|
|
1770
|
+
for (const warning of warnings) {
|
|
1771
|
+
console.log(warning);
|
|
1772
|
+
}
|
|
1773
|
+
if (options.errorOnWarn) {
|
|
1774
|
+
program3.error("Had warnings while checking manifest.");
|
|
1669
1775
|
}
|
|
1670
|
-
cat.blocks = [...cat.blocks, ...category.blocks];
|
|
1671
|
-
categoriesMap.set(cat.name, cat);
|
|
1672
1776
|
}
|
|
1673
1777
|
if (options.output) {
|
|
1778
|
+
loading.start(`Writing output to \`${color8.cyan(outFile)}\``);
|
|
1674
1779
|
fs7.writeFileSync(outFile, JSON.stringify(categories, null, " "));
|
|
1675
|
-
|
|
1676
|
-
loading.stop("Built successfully!");
|
|
1780
|
+
loading.stop(`Wrote output to \`${color8.cyan(outFile)}\``);
|
|
1677
1781
|
}
|
|
1678
1782
|
};
|
|
1679
1783
|
|
|
@@ -1681,7 +1785,7 @@ var _build = async (options) => {
|
|
|
1681
1785
|
import fs8 from "node:fs";
|
|
1682
1786
|
import { cancel as cancel2, confirm as confirm2, isCancel as isCancel2, outro as outro3, spinner as spinner4 } from "@clack/prompts";
|
|
1683
1787
|
import color10 from "chalk";
|
|
1684
|
-
import { Command as Command3, program as
|
|
1788
|
+
import { Command as Command3, program as program4 } from "commander";
|
|
1685
1789
|
import { diffLines } from "diff";
|
|
1686
1790
|
import path8 from "pathe";
|
|
1687
1791
|
import * as v7 from "valibot";
|
|
@@ -1901,7 +2005,7 @@ var _diff = async (options) => {
|
|
|
1901
2005
|
const loading = spinner4();
|
|
1902
2006
|
const config = getConfig(options.cwd).match(
|
|
1903
2007
|
(val) => val,
|
|
1904
|
-
(err) =>
|
|
2008
|
+
(err) => program4.error(color10.red(err))
|
|
1905
2009
|
);
|
|
1906
2010
|
let repoPaths = config.repos;
|
|
1907
2011
|
if (options.repo) repoPaths = [options.repo];
|
|
@@ -1920,7 +2024,7 @@ var _diff = async (options) => {
|
|
|
1920
2024
|
(val) => val,
|
|
1921
2025
|
({ repo, message }) => {
|
|
1922
2026
|
loading.stop(`Failed fetching blocks from ${color10.cyan(repo)}`);
|
|
1923
|
-
|
|
2027
|
+
program4.error(color10.red(message));
|
|
1924
2028
|
}
|
|
1925
2029
|
);
|
|
1926
2030
|
loading.stop(`Retrieved blocks from ${color10.cyan(repoPaths.join(", "))}`);
|
|
@@ -1946,7 +2050,7 @@ var _diff = async (options) => {
|
|
|
1946
2050
|
const rawUrl = await providerInfo.provider.resolveRaw(providerInfo, sourcePath);
|
|
1947
2051
|
const response = await fetch(rawUrl);
|
|
1948
2052
|
if (!response.ok) {
|
|
1949
|
-
|
|
2053
|
+
program4.error(color10.red(`There was an error trying to get ${fullSpecifier}`));
|
|
1950
2054
|
}
|
|
1951
2055
|
let remoteContent = await response.text();
|
|
1952
2056
|
const directory = path8.join(options.cwd, config.path, block.category);
|
|
@@ -1999,7 +2103,7 @@ ${prefix?.() ?? ""}
|
|
|
1999
2103
|
break;
|
|
2000
2104
|
}
|
|
2001
2105
|
if (!found) {
|
|
2002
|
-
|
|
2106
|
+
program4.error(
|
|
2003
2107
|
color10.red(`Invalid block! ${color10.bold(blockSpecifier)} does not exist!`)
|
|
2004
2108
|
);
|
|
2005
2109
|
}
|
|
@@ -2010,7 +2114,7 @@ ${prefix?.() ?? ""}
|
|
|
2010
2114
|
import fs9 from "node:fs";
|
|
2011
2115
|
import { cancel as cancel3, confirm as confirm3, isCancel as isCancel3, outro as outro4, select, spinner as spinner5, text } from "@clack/prompts";
|
|
2012
2116
|
import color11 from "chalk";
|
|
2013
|
-
import { Command as Command4, program as
|
|
2117
|
+
import { Command as Command4, program as program5 } from "commander";
|
|
2014
2118
|
import { detect as detect2, resolveCommand as resolveCommand3 } from "package-manager-detector";
|
|
2015
2119
|
import path9 from "pathe";
|
|
2016
2120
|
import * as v8 from "valibot";
|
|
@@ -2032,7 +2136,7 @@ var init = new Command4("init").description("Initializes your project with a con
|
|
|
2032
2136
|
const options = v8.parse(schema5, opts);
|
|
2033
2137
|
_intro(context.package.version);
|
|
2034
2138
|
if (options.registry !== void 0 && options.project !== void 0) {
|
|
2035
|
-
|
|
2139
|
+
program5.error(
|
|
2036
2140
|
color11.red(
|
|
2037
2141
|
`You cannot provide both ${color11.bold("--project")} and ${color11.bold("--registry")} at the same time.`
|
|
2038
2142
|
)
|
|
@@ -2139,7 +2243,7 @@ var _initRegistry = async (options) => {
|
|
|
2139
2243
|
}
|
|
2140
2244
|
const packagePath = path9.join(options.cwd, "package.json");
|
|
2141
2245
|
if (!fs9.existsSync(packagePath)) {
|
|
2142
|
-
|
|
2246
|
+
program5.error(color11.red(`Couldn't find your ${color11.bold("package.json")}!`));
|
|
2143
2247
|
}
|
|
2144
2248
|
const pkg = JSON.parse(fs9.readFileSync(packagePath).toString());
|
|
2145
2249
|
const scriptAlreadyExists = pkg.scripts !== void 0 && pkg.scripts[options.script] !== void 0;
|
|
@@ -2188,7 +2292,7 @@ var _initRegistry = async (options) => {
|
|
|
2188
2292
|
buildScript += "jsrepo build ";
|
|
2189
2293
|
} else {
|
|
2190
2294
|
const command = resolveCommand3(pm, "execute", ["jsrepo", "build"]);
|
|
2191
|
-
if (!command)
|
|
2295
|
+
if (!command) program5.error(color11.red(`Error resolving execute command for ${pm}`));
|
|
2192
2296
|
buildScript += `${command.command} ${command.args.join(" ")} `;
|
|
2193
2297
|
}
|
|
2194
2298
|
if (options.path !== "./build") {
|
|
@@ -2202,7 +2306,7 @@ var _initRegistry = async (options) => {
|
|
|
2202
2306
|
try {
|
|
2203
2307
|
fs9.writeFileSync(packagePath, JSON.stringify(pkg, null, " "));
|
|
2204
2308
|
} catch (err) {
|
|
2205
|
-
|
|
2309
|
+
program5.error(color11.red(`Error writing to \`${color11.bold(packagePath)}\`. Error: ${err}`));
|
|
2206
2310
|
}
|
|
2207
2311
|
loading.stop(`Added \`${color11.cyan(options.script)}\` to scripts in package.json`);
|
|
2208
2312
|
let installed = alreadyInstalled;
|
|
@@ -2231,7 +2335,7 @@ var _initRegistry = async (options) => {
|
|
|
2231
2335
|
() => loading.stop(`Installed ${JSREPO}.`),
|
|
2232
2336
|
(err) => {
|
|
2233
2337
|
loading.stop(`Failed to install ${JSREPO}.`);
|
|
2234
|
-
|
|
2338
|
+
program5.error(err);
|
|
2235
2339
|
}
|
|
2236
2340
|
);
|
|
2237
2341
|
installed = true;
|
|
@@ -2258,7 +2362,7 @@ var _initRegistry = async (options) => {
|
|
|
2258
2362
|
import fs10 from "node:fs";
|
|
2259
2363
|
import { cancel as cancel4, confirm as confirm4, isCancel as isCancel4, outro as outro5, spinner as spinner6 } from "@clack/prompts";
|
|
2260
2364
|
import color12 from "chalk";
|
|
2261
|
-
import { Argument, Command as Command5, program as
|
|
2365
|
+
import { Argument, Command as Command5, program as program6 } from "commander";
|
|
2262
2366
|
import { execa as execa2 } from "execa";
|
|
2263
2367
|
import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
|
|
2264
2368
|
import { detect as detect3 } from "package-manager-detector/detect";
|
|
@@ -2287,7 +2391,7 @@ var _test = async (blockNames, options) => {
|
|
|
2287
2391
|
verbose(`Attempting to test ${JSON.stringify(blockNames)}`);
|
|
2288
2392
|
const config = getConfig(options.cwd).match(
|
|
2289
2393
|
(val) => val,
|
|
2290
|
-
(err) =>
|
|
2394
|
+
(err) => program6.error(color12.red(err))
|
|
2291
2395
|
);
|
|
2292
2396
|
const loading = spinner6();
|
|
2293
2397
|
const blocksMap = /* @__PURE__ */ new Map();
|
|
@@ -2308,14 +2412,14 @@ var _test = async (blockNames, options) => {
|
|
|
2308
2412
|
for (const repo of repoPaths) {
|
|
2309
2413
|
const providerInfo = (await getProviderInfo(repo)).match(
|
|
2310
2414
|
(info) => info,
|
|
2311
|
-
(err) =>
|
|
2415
|
+
(err) => program6.error(color12.red(err))
|
|
2312
2416
|
);
|
|
2313
2417
|
const manifestUrl = await providerInfo.provider.resolveRaw(providerInfo, OUTPUT_FILE);
|
|
2314
2418
|
verbose(`Got info for provider ${color12.cyan(providerInfo.name)}`);
|
|
2315
2419
|
const response = await fetch(manifestUrl);
|
|
2316
2420
|
if (!response.ok) {
|
|
2317
2421
|
if (!options.verbose) loading.stop(`Error fetching ${color12.cyan(manifestUrl.href)}`);
|
|
2318
|
-
|
|
2422
|
+
program6.error(
|
|
2319
2423
|
color12.red(
|
|
2320
2424
|
`There was an error fetching the \`${OUTPUT_FILE}\` from the repository ${color12.cyan(
|
|
2321
2425
|
repo
|
|
@@ -2355,7 +2459,7 @@ var _test = async (blockNames, options) => {
|
|
|
2355
2459
|
}
|
|
2356
2460
|
if (testingBlocks.length === 0) {
|
|
2357
2461
|
cleanUp();
|
|
2358
|
-
|
|
2462
|
+
program6.error(color12.red("There were no blocks found in your project!"));
|
|
2359
2463
|
}
|
|
2360
2464
|
const testingBlocksMapped = [];
|
|
2361
2465
|
for (const blockSpecifier of testingBlocks) {
|
|
@@ -2381,7 +2485,7 @@ var _test = async (blockNames, options) => {
|
|
|
2381
2485
|
}
|
|
2382
2486
|
const providerInfo = (await getProviderInfo(repo)).match(
|
|
2383
2487
|
(val) => val,
|
|
2384
|
-
(err) =>
|
|
2488
|
+
(err) => program6.error(color12.red(err))
|
|
2385
2489
|
);
|
|
2386
2490
|
const manifestUrl = await providerInfo.provider.resolveRaw(
|
|
2387
2491
|
providerInfo,
|
|
@@ -2389,7 +2493,7 @@ var _test = async (blockNames, options) => {
|
|
|
2389
2493
|
);
|
|
2390
2494
|
const categories = (await getManifest(manifestUrl)).match(
|
|
2391
2495
|
(val) => val,
|
|
2392
|
-
(err) =>
|
|
2496
|
+
(err) => program6.error(color12.red(err))
|
|
2393
2497
|
);
|
|
2394
2498
|
for (const category of categories) {
|
|
2395
2499
|
for (const block2 of category.blocks) {
|
|
@@ -2406,7 +2510,7 @@ var _test = async (blockNames, options) => {
|
|
|
2406
2510
|
block = blocksMap.get(blockSpecifier);
|
|
2407
2511
|
}
|
|
2408
2512
|
if (!block) {
|
|
2409
|
-
|
|
2513
|
+
program6.error(
|
|
2410
2514
|
color12.red(`Invalid block! ${color12.bold(blockSpecifier)} does not exist!`)
|
|
2411
2515
|
);
|
|
2412
2516
|
}
|
|
@@ -2426,7 +2530,7 @@ var _test = async (blockNames, options) => {
|
|
|
2426
2530
|
const response = await fetch(rawUrl);
|
|
2427
2531
|
if (!response.ok) {
|
|
2428
2532
|
loading.stop(color12.red(`Error fetching ${color12.bold(rawUrl.href)}`));
|
|
2429
|
-
|
|
2533
|
+
program6.error(color12.red(`There was an error trying to get ${specifier}`));
|
|
2430
2534
|
}
|
|
2431
2535
|
return await response.text();
|
|
2432
2536
|
};
|
|
@@ -2477,11 +2581,11 @@ var _test = async (blockNames, options) => {
|
|
|
2477
2581
|
verbose("Beginning testing");
|
|
2478
2582
|
const pm = await detect3({ cwd: options.cwd });
|
|
2479
2583
|
if (pm == null) {
|
|
2480
|
-
|
|
2584
|
+
program6.error(color12.red("Could not detect package manager"));
|
|
2481
2585
|
}
|
|
2482
2586
|
const resolved = resolveCommand4(pm.agent, "execute", ["vitest", "run", tempTestDirectory]);
|
|
2483
2587
|
if (resolved == null) {
|
|
2484
|
-
|
|
2588
|
+
program6.error(color12.red(`Could not resolve add command for '${pm.agent}'.`));
|
|
2485
2589
|
}
|
|
2486
2590
|
const { command, args } = resolved;
|
|
2487
2591
|
const testCommand = `${command} ${args.join(" ")}`;
|
|
@@ -2506,7 +2610,7 @@ var _test = async (blockNames, options) => {
|
|
|
2506
2610
|
} else {
|
|
2507
2611
|
cleanUp();
|
|
2508
2612
|
}
|
|
2509
|
-
|
|
2613
|
+
program6.error(color12.red(`Tests failed! Error ${err}`));
|
|
2510
2614
|
}
|
|
2511
2615
|
};
|
|
2512
2616
|
|
|
@@ -2514,7 +2618,7 @@ var _test = async (blockNames, options) => {
|
|
|
2514
2618
|
import fs11 from "node:fs";
|
|
2515
2619
|
import { cancel as cancel5, confirm as confirm5, isCancel as isCancel5, multiselect as multiselect2, outro as outro6, spinner as spinner7 } from "@clack/prompts";
|
|
2516
2620
|
import color13 from "chalk";
|
|
2517
|
-
import { Command as Command6, program as
|
|
2621
|
+
import { Command as Command6, program as program7 } from "commander";
|
|
2518
2622
|
import { diffLines as diffLines2 } from "diff";
|
|
2519
2623
|
import { resolveCommand as resolveCommand5 } from "package-manager-detector/commands";
|
|
2520
2624
|
import { detect as detect4 } from "package-manager-detector/detect";
|
|
@@ -2552,13 +2656,13 @@ var _update = async (blockNames, options) => {
|
|
|
2552
2656
|
const loading = spinner7();
|
|
2553
2657
|
const config = getConfig(options.cwd).match(
|
|
2554
2658
|
(val) => val,
|
|
2555
|
-
(err) =>
|
|
2659
|
+
(err) => program7.error(color13.red(err))
|
|
2556
2660
|
);
|
|
2557
2661
|
let repoPaths = config.repos;
|
|
2558
2662
|
if (options.repo) repoPaths = [options.repo];
|
|
2559
2663
|
for (const blockSpecifier of blockNames) {
|
|
2560
2664
|
if (blockSpecifier.startsWith("github")) {
|
|
2561
|
-
|
|
2665
|
+
program7.error(
|
|
2562
2666
|
color13.red(
|
|
2563
2667
|
`Invalid value provided for block names \`${color13.bold(blockSpecifier)}\`. Block names are expected to be provided in the format of \`${color13.bold("<category>/<name>")}\``
|
|
2564
2668
|
)
|
|
@@ -2581,7 +2685,7 @@ var _update = async (blockNames, options) => {
|
|
|
2581
2685
|
(val) => val,
|
|
2582
2686
|
({ repo, message }) => {
|
|
2583
2687
|
loading.stop(`Failed fetching blocks from ${color13.cyan(repo)}`);
|
|
2584
|
-
|
|
2688
|
+
program7.error(color13.red(message));
|
|
2585
2689
|
}
|
|
2586
2690
|
);
|
|
2587
2691
|
if (!options.verbose) loading.stop(`Retrieved blocks from ${color13.cyan(repoPaths.join(", "))}`);
|
|
@@ -2611,7 +2715,7 @@ var _update = async (blockNames, options) => {
|
|
|
2611
2715
|
verbose(`Preparing to update ${color13.cyan(updatingBlockNames.join(", "))}`);
|
|
2612
2716
|
const updatingBlocks = (await resolveTree(updatingBlockNames, blocksMap, repoPaths)).match(
|
|
2613
2717
|
(val) => val,
|
|
2614
|
-
|
|
2718
|
+
program7.error
|
|
2615
2719
|
);
|
|
2616
2720
|
const pm = (await detect4({ cwd: options.cwd }))?.agent ?? "npm";
|
|
2617
2721
|
const tasks = [];
|
|
@@ -2629,7 +2733,7 @@ var _update = async (blockNames, options) => {
|
|
|
2629
2733
|
const response = await fetch(rawUrl);
|
|
2630
2734
|
if (!response.ok) {
|
|
2631
2735
|
loading.stop(color13.red(`Error fetching ${color13.bold(rawUrl.href)}`));
|
|
2632
|
-
|
|
2736
|
+
program7.error(color13.red(`There was an error trying to get ${fullSpecifier}`));
|
|
2633
2737
|
}
|
|
2634
2738
|
return await response.text();
|
|
2635
2739
|
};
|
|
@@ -2772,7 +2876,7 @@ ${prefix?.() ?? ""}
|
|
|
2772
2876
|
},
|
|
2773
2877
|
(err) => {
|
|
2774
2878
|
if (!options.verbose) loading.stop("Failed to install dependencies");
|
|
2775
|
-
|
|
2879
|
+
program7.error(err);
|
|
2776
2880
|
}
|
|
2777
2881
|
);
|
|
2778
2882
|
}
|
|
@@ -2791,7 +2895,7 @@ ${prefix?.() ?? ""}
|
|
|
2791
2895
|
},
|
|
2792
2896
|
(err) => {
|
|
2793
2897
|
if (!options.verbose) loading.stop("Failed to install dev dependencies");
|
|
2794
|
-
|
|
2898
|
+
program7.error(err);
|
|
2795
2899
|
}
|
|
2796
2900
|
);
|
|
2797
2901
|
}
|
|
@@ -2838,8 +2942,8 @@ var context = {
|
|
|
2838
2942
|
},
|
|
2839
2943
|
resolveRelativeToRoot
|
|
2840
2944
|
};
|
|
2841
|
-
|
|
2842
|
-
|
|
2945
|
+
program8.name(name).description(description).version(version).addCommand(add).addCommand(init).addCommand(test).addCommand(build).addCommand(update).addCommand(diff);
|
|
2946
|
+
program8.parse();
|
|
2843
2947
|
export {
|
|
2844
2948
|
context
|
|
2845
2949
|
};
|
package/package.json
CHANGED
package/src/commands/build.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { outro, spinner } from '@clack/prompts';
|
|
3
3
|
import color from 'chalk';
|
|
4
|
-
import { Command } from 'commander';
|
|
4
|
+
import { Command, program } from 'commander';
|
|
5
5
|
import path from 'pathe';
|
|
6
6
|
import * as v from 'valibot';
|
|
7
7
|
import { context } from '..';
|
|
8
|
+
import * as ascii from '../utils/ascii';
|
|
8
9
|
import { type Category, buildBlocksDirectory } from '../utils/build';
|
|
9
10
|
import { OUTPUT_FILE } from '../utils/context';
|
|
10
11
|
import { intro } from '../utils/prompts';
|
|
11
12
|
|
|
12
13
|
const schema = v.object({
|
|
13
14
|
dirs: v.array(v.string()),
|
|
15
|
+
includeBlocks: v.array(v.string()),
|
|
16
|
+
includeCategories: v.array(v.string()),
|
|
14
17
|
excludeDeps: v.array(v.string()),
|
|
15
18
|
output: v.boolean(),
|
|
19
|
+
errorOnWarn: v.boolean(),
|
|
16
20
|
verbose: v.boolean(),
|
|
17
21
|
cwd: v.string(),
|
|
18
22
|
});
|
|
@@ -22,8 +26,19 @@ type Options = v.InferInput<typeof schema>;
|
|
|
22
26
|
const build = new Command('build')
|
|
23
27
|
.description(`Builds the provided --dirs in the project root into a \`${OUTPUT_FILE}\` file.`)
|
|
24
28
|
.option('--dirs [dirs...]', 'The directories containing the blocks.', ['./blocks'])
|
|
29
|
+
.option('--include-blocks [blockNames...]', 'Include only the blocks with these names.', [])
|
|
30
|
+
.option(
|
|
31
|
+
'--include-categories [categoryNames...]',
|
|
32
|
+
'Include only the categories with these names.',
|
|
33
|
+
[]
|
|
34
|
+
)
|
|
25
35
|
.option('--exclude-deps [deps...]', 'Dependencies that should not be added.', [])
|
|
26
36
|
.option('--no-output', `Do not output a \`${OUTPUT_FILE}\` file.`)
|
|
37
|
+
.option(
|
|
38
|
+
'--error-on-warn',
|
|
39
|
+
'If there is a warning throw an error and do not allow build to complete.',
|
|
40
|
+
false
|
|
41
|
+
)
|
|
27
42
|
.option('--verbose', 'Include debug logs.', false)
|
|
28
43
|
.option('--cwd <path>', 'The current working directory.', process.cwd())
|
|
29
44
|
.action(async (opts) => {
|
|
@@ -50,33 +65,102 @@ const _build = async (options: Options) => {
|
|
|
50
65
|
|
|
51
66
|
if (options.output && fs.existsSync(outFile)) fs.rmSync(outFile);
|
|
52
67
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
)
|
|
68
|
+
const builtCategories = buildBlocksDirectory(dirPath, { ...options });
|
|
69
|
+
|
|
70
|
+
for (const category of builtCategories) {
|
|
71
|
+
if (categories.find((cat) => cat.name === category.name) !== undefined) {
|
|
72
|
+
const error = 'a category with the same name already exists!';
|
|
73
|
+
|
|
74
|
+
if (options.errorOnWarn) {
|
|
75
|
+
program.error(
|
|
76
|
+
color.red(
|
|
77
|
+
`\`${color.bold(`${dir}/${category.name}`)}\` could not be added because ${error}`
|
|
78
|
+
)
|
|
79
|
+
);
|
|
80
|
+
} else {
|
|
81
|
+
console.warn(
|
|
82
|
+
`${ascii.VERTICAL_LINE} ${ascii.WARN} Skipped adding \`${color.cyan(`${dir}/${category.name}`)}\` because ${error}`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
categories.push(category);
|
|
89
|
+
}
|
|
56
90
|
|
|
57
91
|
loading.stop(`Built ${color.cyan(dirPath)}`);
|
|
58
92
|
}
|
|
59
93
|
|
|
60
|
-
|
|
94
|
+
loading.start('Checking manifest');
|
|
61
95
|
|
|
62
|
-
|
|
63
|
-
const cat = categoriesMap.get(category.name);
|
|
96
|
+
const warnings: string[] = [];
|
|
64
97
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
98
|
+
for (const category of categories) {
|
|
99
|
+
for (const block of category.blocks) {
|
|
100
|
+
// lookup local deps
|
|
101
|
+
for (const dep of block.localDependencies) {
|
|
102
|
+
const [depCategoryName, depBlockName] = dep.split('/');
|
|
103
|
+
|
|
104
|
+
const depCategory = categories.find(
|
|
105
|
+
(cat) => cat.name.trim() === depCategoryName.trim()
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const invalidDependencyError = () => {
|
|
109
|
+
const error = `depends on ${color.bold(dep)} which doesn't exist!`;
|
|
110
|
+
|
|
111
|
+
if (options.errorOnWarn) {
|
|
112
|
+
warnings.push(
|
|
113
|
+
color.red(`${color.bold(`${category.name}/${block.name}`)} ${error}`)
|
|
114
|
+
);
|
|
115
|
+
} else {
|
|
116
|
+
warnings.push(
|
|
117
|
+
`${ascii.VERTICAL_LINE} ${ascii.WARN} ${color.bold(`${category.name}/${block.name}`)} ${error}`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
if (!depCategory) {
|
|
123
|
+
invalidDependencyError();
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (depCategory.blocks.find((b) => b.name === depBlockName) === undefined) {
|
|
128
|
+
invalidDependencyError();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
for (const dep of [...block.dependencies, ...block.devDependencies]) {
|
|
133
|
+
if (!dep.includes('@')) {
|
|
134
|
+
const error = `You haven't installed ${color.bold(dep)} as a dependency so your users could get any version of it when they install your block!`;
|
|
135
|
+
|
|
136
|
+
if (options.errorOnWarn) {
|
|
137
|
+
warnings.push(color.red(error));
|
|
138
|
+
} else {
|
|
139
|
+
warnings.push(`${ascii.VERTICAL_LINE} ${ascii.WARN} ${error}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
68
143
|
}
|
|
144
|
+
}
|
|
69
145
|
|
|
70
|
-
|
|
71
|
-
cat.blocks = [...cat.blocks, ...category.blocks];
|
|
146
|
+
loading.stop('Completed checking manifest.');
|
|
72
147
|
|
|
73
|
-
|
|
148
|
+
if (warnings.length > 0) {
|
|
149
|
+
for (const warning of warnings) {
|
|
150
|
+
console.log(warning);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (options.errorOnWarn) {
|
|
154
|
+
program.error('Had warnings while checking manifest.');
|
|
155
|
+
}
|
|
74
156
|
}
|
|
75
157
|
|
|
76
158
|
if (options.output) {
|
|
159
|
+
loading.start(`Writing output to \`${color.cyan(outFile)}\``);
|
|
160
|
+
|
|
77
161
|
fs.writeFileSync(outFile, JSON.stringify(categories, null, '\t'));
|
|
78
|
-
|
|
79
|
-
loading.stop(
|
|
162
|
+
|
|
163
|
+
loading.stop(`Wrote output to \`${color.cyan(outFile)}\``);
|
|
80
164
|
}
|
|
81
165
|
};
|
|
82
166
|
|
package/src/utils/build.ts
CHANGED
|
@@ -36,6 +36,9 @@ const isTestFile = (file: string): boolean =>
|
|
|
36
36
|
type Options = {
|
|
37
37
|
cwd: string;
|
|
38
38
|
excludeDeps: string[];
|
|
39
|
+
includeBlocks: string[];
|
|
40
|
+
includeCategories: string[];
|
|
41
|
+
errorOnWarn: boolean;
|
|
39
42
|
};
|
|
40
43
|
|
|
41
44
|
/** Using the provided path to the blocks folder builds the blocks into categories and also resolves dependencies
|
|
@@ -43,7 +46,10 @@ type Options = {
|
|
|
43
46
|
* @param blocksPath
|
|
44
47
|
* @returns
|
|
45
48
|
*/
|
|
46
|
-
const buildBlocksDirectory = (
|
|
49
|
+
const buildBlocksDirectory = (
|
|
50
|
+
blocksPath: string,
|
|
51
|
+
{ cwd, excludeDeps, includeBlocks, includeCategories, errorOnWarn }: Options
|
|
52
|
+
): Category[] => {
|
|
47
53
|
let paths: string[];
|
|
48
54
|
|
|
49
55
|
try {
|
|
@@ -61,6 +67,13 @@ const buildBlocksDirectory = (blocksPath: string, { cwd, excludeDeps }: Options)
|
|
|
61
67
|
|
|
62
68
|
const categoryName = path.basename(categoryPath);
|
|
63
69
|
|
|
70
|
+
// if includeCategories enabled and block is not part of includeCategories skip adding it
|
|
71
|
+
if (
|
|
72
|
+
includeCategories.length > 0 &&
|
|
73
|
+
includeCategories.find((val) => val.trim() === categoryName.trim()) === undefined
|
|
74
|
+
)
|
|
75
|
+
continue;
|
|
76
|
+
|
|
64
77
|
const category: Category = {
|
|
65
78
|
name: categoryName,
|
|
66
79
|
blocks: [],
|
|
@@ -74,19 +87,39 @@ const buildBlocksDirectory = (blocksPath: string, { cwd, excludeDeps }: Options)
|
|
|
74
87
|
if (fs.statSync(blockDir).isFile()) {
|
|
75
88
|
if (isTestFile(file)) continue;
|
|
76
89
|
|
|
90
|
+
const name = path.parse(path.basename(file)).name;
|
|
91
|
+
|
|
92
|
+
// if includeBlocks enabled and block is not part of includeBlocks skip adding it
|
|
93
|
+
if (
|
|
94
|
+
includeBlocks.length > 0 &&
|
|
95
|
+
includeBlocks.find((val) => val.trim() === name.trim()) === undefined
|
|
96
|
+
)
|
|
97
|
+
continue;
|
|
98
|
+
|
|
77
99
|
const lang = languages.find((resolver) => resolver.matches(file));
|
|
78
100
|
|
|
79
101
|
if (!lang) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
const error = 'files are not currently supported!';
|
|
103
|
+
|
|
104
|
+
if (errorOnWarn) {
|
|
105
|
+
program.error(
|
|
106
|
+
color.red(
|
|
107
|
+
`Couldn't add \`${color.bold(blockDir)}\` \`*${color.bold(
|
|
108
|
+
path.parse(file).ext
|
|
109
|
+
)}\` ${error}`
|
|
110
|
+
)
|
|
111
|
+
);
|
|
112
|
+
} else {
|
|
113
|
+
console.warn(
|
|
114
|
+
`${ascii.VERTICAL_LINE} ${ascii.WARN} Skipped \`${color.bold(blockDir)}\` \`*${color.bold(
|
|
115
|
+
path.parse(file).ext
|
|
116
|
+
)}\` ${error}`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
85
120
|
continue;
|
|
86
121
|
}
|
|
87
122
|
|
|
88
|
-
const name = path.parse(path.basename(file)).name;
|
|
89
|
-
|
|
90
123
|
// tries to find a test file with the same name as the file
|
|
91
124
|
const testsPath = files.find((f) =>
|
|
92
125
|
TEST_SUFFIXES.find((suffix) => f === `${name}${suffix}`)
|
|
@@ -126,6 +159,13 @@ const buildBlocksDirectory = (blocksPath: string, { cwd, excludeDeps }: Options)
|
|
|
126
159
|
} else {
|
|
127
160
|
const blockName = file;
|
|
128
161
|
|
|
162
|
+
// if includeBlocks enabled and block is not part of includeBlocks skip adding it
|
|
163
|
+
if (
|
|
164
|
+
includeBlocks.length > 0 &&
|
|
165
|
+
includeBlocks.find((val) => val.trim() === blockName.trim()) === undefined
|
|
166
|
+
)
|
|
167
|
+
continue;
|
|
168
|
+
|
|
129
169
|
const blockFiles = fs.readdirSync(blockDir);
|
|
130
170
|
|
|
131
171
|
const hasTests = blockFiles.findIndex((f) => isTestFile(f)) !== -1;
|
|
@@ -139,20 +179,42 @@ const buildBlocksDirectory = (blocksPath: string, { cwd, excludeDeps }: Options)
|
|
|
139
179
|
if (isTestFile(f)) continue;
|
|
140
180
|
|
|
141
181
|
if (fs.statSync(path.join(blockDir, f)).isDirectory()) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
)
|
|
182
|
+
const error = 'subdirectories are not currently supported!';
|
|
183
|
+
|
|
184
|
+
if (errorOnWarn) {
|
|
185
|
+
program.error(
|
|
186
|
+
color.red(
|
|
187
|
+
`Couldn't add \`${color.bold(path.join(blockDir, f))}\` ${error}`
|
|
188
|
+
)
|
|
189
|
+
);
|
|
190
|
+
} else {
|
|
191
|
+
console.warn(
|
|
192
|
+
`${ascii.VERTICAL_LINE} ${ascii.WARN} Skipped \`${color.bold(path.join(blockDir, f))}\` ${error}`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
145
195
|
continue;
|
|
146
196
|
}
|
|
147
197
|
|
|
148
198
|
const lang = languages.find((resolver) => resolver.matches(f));
|
|
149
199
|
|
|
150
200
|
if (!lang) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
201
|
+
const error = 'files are not currently supported!';
|
|
202
|
+
|
|
203
|
+
if (errorOnWarn) {
|
|
204
|
+
program.error(
|
|
205
|
+
color.red(
|
|
206
|
+
`Couldn't add \`${color.bold(path.join(blockDir, f))}\` \`*${color.bold(
|
|
207
|
+
path.parse(f).ext
|
|
208
|
+
)}\` ${error}`
|
|
209
|
+
)
|
|
210
|
+
);
|
|
211
|
+
} else {
|
|
212
|
+
console.warn(
|
|
213
|
+
`${ascii.VERTICAL_LINE} ${ascii.WARN} Skipped \`${path.join(blockDir, f)}\` \`*${color.bold(
|
|
214
|
+
path.parse(f).ext
|
|
215
|
+
)}\` ${error}`
|
|
216
|
+
);
|
|
217
|
+
}
|
|
156
218
|
continue;
|
|
157
219
|
}
|
|
158
220
|
|