intor-cli 0.0.1
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 +46 -0
- package/package.json +73 -0
- package/src/build/build-schemas/build-schemas.ts +13 -0
- package/src/build/build-schemas/index.ts +1 -0
- package/src/build/build-types/build-types.ts +46 -0
- package/src/build/build-types/index.ts +1 -0
- package/src/build/build-types/output/append-config-block.ts +34 -0
- package/src/build/build-types/output/append-footer.ts +5 -0
- package/src/build/build-types/output/append-header.ts +11 -0
- package/src/build/build-types/output/index.ts +3 -0
- package/src/build/build-types/utils/indent.ts +3 -0
- package/src/build/build-types/utils/render-infer-node.ts +29 -0
- package/src/build/index.ts +3 -0
- package/src/build/types.ts +19 -0
- package/src/cli/commands/check.ts +50 -0
- package/src/cli/commands/generate.ts +61 -0
- package/src/cli/index.ts +24 -0
- package/src/core/collect-messages/collect-runtime-messages.ts +76 -0
- package/src/core/collect-messages/index.ts +1 -0
- package/src/core/collect-messages/readers.ts +23 -0
- package/src/core/collect-messages/resolve-messages-reader.ts +57 -0
- package/src/core/constants/extra-exts.ts +2 -0
- package/src/core/constants/generated-files.ts +3 -0
- package/src/core/constants/index.ts +7 -0
- package/src/core/diagnostics/collect.ts +59 -0
- package/src/core/diagnostics/group.ts +41 -0
- package/src/core/diagnostics/index.ts +2 -0
- package/src/core/diagnostics/messages.ts +51 -0
- package/src/core/diagnostics/rules/enforce-missing-replacements.ts +55 -0
- package/src/core/diagnostics/rules/enforce-missing-rich.ts +55 -0
- package/src/core/diagnostics/rules/key/empty.ts +34 -0
- package/src/core/diagnostics/rules/key/index.ts +2 -0
- package/src/core/diagnostics/rules/key/not-found.ts +43 -0
- package/src/core/diagnostics/rules/replacement/index.ts +3 -0
- package/src/core/diagnostics/rules/replacement/missing.ts +48 -0
- package/src/core/diagnostics/rules/replacement/not-allowed.ts +43 -0
- package/src/core/diagnostics/rules/replacement/unused.ts +48 -0
- package/src/core/diagnostics/rules/rich/index.ts +3 -0
- package/src/core/diagnostics/rules/rich/missing.ts +48 -0
- package/src/core/diagnostics/rules/rich/not-allowed.ts +43 -0
- package/src/core/diagnostics/rules/rich/unused.ts +48 -0
- package/src/core/diagnostics/types.ts +21 -0
- package/src/core/diagnostics/utils/get-schema-node-at-path.ts +29 -0
- package/src/core/diagnostics/utils/index-usages-by-key.ts +28 -0
- package/src/core/diagnostics/utils/resolve-key-path.ts +5 -0
- package/src/core/discover-configs/discover-configs.ts +87 -0
- package/src/core/discover-configs/index.ts +1 -0
- package/src/core/discover-configs/is-intor-resolved-config.ts +15 -0
- package/src/core/extract-usages/README.md +84 -0
- package/src/core/extract-usages/collectors/collect-key-usages.ts +40 -0
- package/src/core/extract-usages/collectors/collect-pre-keys.ts +58 -0
- package/src/core/extract-usages/collectors/collect-replacement-usages.ts +68 -0
- package/src/core/extract-usages/collectors/collect-rich-usages.ts +57 -0
- package/src/core/extract-usages/collectors/collect-translator-bindings.ts +56 -0
- package/src/core/extract-usages/collectors/index.ts +5 -0
- package/src/core/extract-usages/collectors/utils/extract-static-object-keys.ts +31 -0
- package/src/core/extract-usages/collectors/utils/get-config-key.ts +15 -0
- package/src/core/extract-usages/collectors/utils/get-object-arg.ts +42 -0
- package/src/core/extract-usages/collectors/utils/is-static-string-literal.ts +26 -0
- package/src/core/extract-usages/collectors/utils/walk-translator-bindings.ts +47 -0
- package/src/core/extract-usages/collectors/utils/walk-translator-method-calls.ts +42 -0
- package/src/core/extract-usages/extract-usages.ts +88 -0
- package/src/core/extract-usages/index.ts +13 -0
- package/src/core/extract-usages/load-source-files-from-tscofnig.ts +76 -0
- package/src/core/extract-usages/translator-registry.ts +20 -0
- package/src/core/extract-usages/types.ts +53 -0
- package/src/core/index.ts +13 -0
- package/src/core/infer-schema/index.ts +3 -0
- package/src/core/infer-schema/infer-schemas.ts +16 -0
- package/src/core/infer-schema/messages/index.ts +1 -0
- package/src/core/infer-schema/messages/infer-messages-schema.ts +64 -0
- package/src/core/infer-schema/replacements/extract-interpolation-names.ts +70 -0
- package/src/core/infer-schema/replacements/index.ts +1 -0
- package/src/core/infer-schema/replacements/infer-replacements-schema.ts +63 -0
- package/src/core/infer-schema/rich/index.ts +1 -0
- package/src/core/infer-schema/rich/infer-rich-schema.ts +66 -0
- package/src/core/infer-schema/types.ts +42 -0
- package/src/core/infer-schema/utils/infer-object.ts +32 -0
- package/src/core/infer-schema/utils/is-message-object.ts +5 -0
- package/src/core/read-generated-schema.ts +42 -0
- package/src/core/scan-logger.ts +10 -0
- package/src/core/write-generated-files.ts +51 -0
- package/src/features/check/check.ts +75 -0
- package/src/features/check/index.ts +1 -0
- package/src/features/check/print-summary.ts +28 -0
- package/src/features/generate/generate.ts +76 -0
- package/src/features/generate/index.ts +1 -0
- package/src/features/generate/print-configs.ts +8 -0
- package/src/features/generate/print-summary.ts +19 -0
- package/src/features/index.ts +2 -0
- package/src/features/print-title.ts +7 -0
- package/src/features/spinner.ts +3 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result of a semantic inference step.
|
|
3
|
+
*
|
|
4
|
+
* - none: no meaningful type could be inferred (intentionally skipped)
|
|
5
|
+
* - inferred: contains a concrete TypeScript type representation
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type InferNode =
|
|
9
|
+
| InferNoneNode
|
|
10
|
+
| InferPrimitiveNode
|
|
11
|
+
| InferArrayNode
|
|
12
|
+
| InferObjectNode
|
|
13
|
+
| InferRecordNode;
|
|
14
|
+
|
|
15
|
+
export interface InferNoneNode {
|
|
16
|
+
kind: "none";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface InferPrimitiveNode {
|
|
20
|
+
kind: "primitive";
|
|
21
|
+
type: "string" | "number" | "boolean" | "null";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface InferArrayNode {
|
|
25
|
+
kind: "array";
|
|
26
|
+
element: InferNode;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface InferObjectNode {
|
|
30
|
+
kind: "object";
|
|
31
|
+
properties: Record<string, InferNode>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface InferRecordNode {
|
|
35
|
+
kind: "record";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface InferredSchemas {
|
|
39
|
+
messagesSchema: InferNode;
|
|
40
|
+
replacementsSchema: InferNode;
|
|
41
|
+
richSchema: InferNode;
|
|
42
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { InferNode } from "../types";
|
|
2
|
+
import type { MessageObject, MessageValue } from "intor";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Infer an object-like semantic node by aggregating inferred children.
|
|
6
|
+
*
|
|
7
|
+
* - Delegates inference to child nodes
|
|
8
|
+
* - Prunes branches without semantic meaning
|
|
9
|
+
* - Returns `none` if no children remain
|
|
10
|
+
*/
|
|
11
|
+
export function inferObject(
|
|
12
|
+
value: MessageObject,
|
|
13
|
+
inferChild: (value: MessageValue) => InferNode,
|
|
14
|
+
): InferNode {
|
|
15
|
+
const properties: Record<string, InferNode> = {};
|
|
16
|
+
|
|
17
|
+
for (const [key, val] of Object.entries(value)) {
|
|
18
|
+
const child = inferChild(val);
|
|
19
|
+
|
|
20
|
+
// Skip branches without semantic meaning
|
|
21
|
+
if (child.kind === "none") continue;
|
|
22
|
+
|
|
23
|
+
properties[key] = child;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// No inferred children => no semantic result
|
|
27
|
+
if (Object.keys(properties).length === 0) {
|
|
28
|
+
return { kind: "none" };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return { kind: "object", properties };
|
|
32
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { GeneratedSchema } from "../build";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { DEFAULT_OUT_DIR, DEFAULT_SCHEMA_FILE } from "./constants";
|
|
5
|
+
|
|
6
|
+
export interface ReadGeneratedSchemaOptions {
|
|
7
|
+
cwd?: string;
|
|
8
|
+
outDir?: string;
|
|
9
|
+
fileName?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function readGeneratedSchema(
|
|
13
|
+
options: ReadGeneratedSchemaOptions = {},
|
|
14
|
+
): Promise<GeneratedSchema> {
|
|
15
|
+
const {
|
|
16
|
+
cwd = process.cwd(),
|
|
17
|
+
outDir = DEFAULT_OUT_DIR,
|
|
18
|
+
fileName = DEFAULT_SCHEMA_FILE,
|
|
19
|
+
} = options;
|
|
20
|
+
|
|
21
|
+
const schemaPath = path.resolve(cwd, outDir, fileName);
|
|
22
|
+
|
|
23
|
+
let raw: string;
|
|
24
|
+
|
|
25
|
+
// Try to read
|
|
26
|
+
try {
|
|
27
|
+
raw = await fs.readFile(schemaPath, "utf8");
|
|
28
|
+
} catch {
|
|
29
|
+
throw new Error(
|
|
30
|
+
`Failed to read intor schema file at "${schemaPath}".\n Have you run "intor generate"?`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Try to parse
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(raw) as GeneratedSchema;
|
|
37
|
+
} catch {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Invalid JSON format in intor schema file at "${schemaPath}".`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_OUT_DIR,
|
|
5
|
+
DEFAULT_TYPES_FILE,
|
|
6
|
+
DEFAULT_SCHEMA_FILE,
|
|
7
|
+
} from "./constants";
|
|
8
|
+
|
|
9
|
+
export interface WriteOptions {
|
|
10
|
+
cwd?: string;
|
|
11
|
+
outDir?: string;
|
|
12
|
+
typesFileName?: string;
|
|
13
|
+
schemaFileName?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface WriteGeneratedFilesResult {
|
|
17
|
+
outDir: string;
|
|
18
|
+
typesPath: string;
|
|
19
|
+
schemaPath: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function writeGeneratedFiles(
|
|
23
|
+
{ types, schema }: { types: string; schema: unknown },
|
|
24
|
+
options: WriteOptions = {},
|
|
25
|
+
): Promise<WriteGeneratedFilesResult> {
|
|
26
|
+
const {
|
|
27
|
+
cwd = process.cwd(),
|
|
28
|
+
outDir = DEFAULT_OUT_DIR,
|
|
29
|
+
typesFileName = DEFAULT_TYPES_FILE,
|
|
30
|
+
schemaFileName = DEFAULT_SCHEMA_FILE,
|
|
31
|
+
} = options;
|
|
32
|
+
|
|
33
|
+
const resolvedOutDir = path.resolve(cwd, outDir);
|
|
34
|
+
const typesPath = path.join(resolvedOutDir, typesFileName);
|
|
35
|
+
const schemaPath = path.join(resolvedOutDir, schemaFileName);
|
|
36
|
+
|
|
37
|
+
// Ensure .intor directory exists
|
|
38
|
+
await fs.mkdir(resolvedOutDir, { recursive: true });
|
|
39
|
+
|
|
40
|
+
// Write types (as-is)
|
|
41
|
+
await fs.writeFile(typesPath, types, "utf8");
|
|
42
|
+
|
|
43
|
+
// Write schema (pretty JSON for diff / debug)
|
|
44
|
+
await fs.writeFile(schemaPath, JSON.stringify(schema, null, 2), "utf8");
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
outDir: resolvedOutDir,
|
|
48
|
+
typesPath,
|
|
49
|
+
schemaPath,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/* eslint-disable unicorn/no-process-exit */
|
|
2
|
+
import type { ReadGeneratedSchemaOptions } from "../../core";
|
|
3
|
+
import type { ExtractUsagesOptions } from "../../core/extract-usages/extract-usages";
|
|
4
|
+
import {
|
|
5
|
+
readGeneratedSchema,
|
|
6
|
+
extractUsages,
|
|
7
|
+
collectDiagnostics,
|
|
8
|
+
groupDiagnostics,
|
|
9
|
+
} from "../../core";
|
|
10
|
+
import { printTitle } from "../../features/print-title";
|
|
11
|
+
import { spinner } from "../spinner";
|
|
12
|
+
import { printSummary } from "./print-summary";
|
|
13
|
+
|
|
14
|
+
function resolveConfigKey(
|
|
15
|
+
usageConfigKey: string | undefined,
|
|
16
|
+
defaultConfigKey: string,
|
|
17
|
+
) {
|
|
18
|
+
if (usageConfigKey === "__default__") return defaultConfigKey;
|
|
19
|
+
if (usageConfigKey == null) return defaultConfigKey;
|
|
20
|
+
return usageConfigKey;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function check(
|
|
24
|
+
readOptions?: ReadGeneratedSchemaOptions,
|
|
25
|
+
extractOptions?: ExtractUsagesOptions,
|
|
26
|
+
) {
|
|
27
|
+
printTitle("Checking intor diagnostics");
|
|
28
|
+
spinner.start();
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// -----------------------------------------------------------------------
|
|
32
|
+
// Read generated schema
|
|
33
|
+
// -----------------------------------------------------------------------
|
|
34
|
+
const generatedSchema = await readGeneratedSchema(readOptions);
|
|
35
|
+
|
|
36
|
+
// -----------------------------------------------------------------------
|
|
37
|
+
// Extract usages
|
|
38
|
+
// -----------------------------------------------------------------------
|
|
39
|
+
const usages = extractUsages(extractOptions);
|
|
40
|
+
|
|
41
|
+
// Use first config's id as default key
|
|
42
|
+
const defaultConfigKey = generatedSchema.configs[0]?.id;
|
|
43
|
+
|
|
44
|
+
spinner.stop();
|
|
45
|
+
|
|
46
|
+
// Per-config processing
|
|
47
|
+
for (const config of generatedSchema.configs) {
|
|
48
|
+
// configKey <-> config.id
|
|
49
|
+
const configKey = config.id;
|
|
50
|
+
|
|
51
|
+
// per-config usages
|
|
52
|
+
const scopedUsages = {
|
|
53
|
+
keys: usages.keys.filter(
|
|
54
|
+
(u) => resolveConfigKey(u.configKey, defaultConfigKey) === configKey,
|
|
55
|
+
),
|
|
56
|
+
replacements: usages.replacements.filter(
|
|
57
|
+
(u) => resolveConfigKey(u.configKey, defaultConfigKey) === configKey,
|
|
58
|
+
),
|
|
59
|
+
rich: usages.rich.filter(
|
|
60
|
+
(u) => resolveConfigKey(u.configKey, defaultConfigKey) === configKey,
|
|
61
|
+
),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Diagnostic
|
|
65
|
+
const diagnostics = collectDiagnostics(config.schemas, scopedUsages);
|
|
66
|
+
const grouped = groupDiagnostics(diagnostics);
|
|
67
|
+
|
|
68
|
+
printSummary(config.id, grouped);
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
spinner.stop();
|
|
72
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { check } from "./check";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { DiagnosticGroup } from "../../core/diagnostics/types";
|
|
2
|
+
import pc from "picocolors";
|
|
3
|
+
|
|
4
|
+
export function printSummary(configId: string, grouped: DiagnosticGroup[]) {
|
|
5
|
+
// Log header
|
|
6
|
+
console.log(pc.dim("Config:"), pc.cyan(`${configId}\n`));
|
|
7
|
+
|
|
8
|
+
// Log no issues
|
|
9
|
+
if (grouped.length === 0) {
|
|
10
|
+
console.log(pc.dim("✔ Diagnostics completed with no issues.\n"));
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Log problems
|
|
15
|
+
for (const group of grouped) {
|
|
16
|
+
const { method, messageKey, problems, file, lines } = group;
|
|
17
|
+
|
|
18
|
+
const header = `${messageKey} ${`(${method})`}\n`;
|
|
19
|
+
|
|
20
|
+
const problemsLine = [
|
|
21
|
+
...problems.map((p) => pc.gray(` - ${p}`)),
|
|
22
|
+
pc.dim(` ➜ ${file}:${lines.join(",")}`),
|
|
23
|
+
"",
|
|
24
|
+
].join("\n");
|
|
25
|
+
|
|
26
|
+
console.log(header + problemsLine);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* eslint-disable unicorn/no-process-exit */
|
|
2
|
+
import type { ExtraExt } from "../../core";
|
|
3
|
+
import { buildTypes, buildSchemas, type BuildInput } from "../../build";
|
|
4
|
+
import {
|
|
5
|
+
discoverConfigs,
|
|
6
|
+
collectRuntimeMessages,
|
|
7
|
+
inferSchemas,
|
|
8
|
+
writeGeneratedFiles,
|
|
9
|
+
} from "../../core";
|
|
10
|
+
import { printTitle } from "../print-title";
|
|
11
|
+
import { spinner } from "../spinner";
|
|
12
|
+
import { printConfigs } from "./print-configs";
|
|
13
|
+
import { printSummary } from "./print-summary";
|
|
14
|
+
|
|
15
|
+
export interface GenerateOptions {
|
|
16
|
+
exts?: Array<ExtraExt>;
|
|
17
|
+
customReaders?: Record<string, string>;
|
|
18
|
+
debug?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function generate({
|
|
22
|
+
exts = [],
|
|
23
|
+
customReaders,
|
|
24
|
+
debug,
|
|
25
|
+
}: GenerateOptions) {
|
|
26
|
+
printTitle("Generating intor types");
|
|
27
|
+
spinner.start();
|
|
28
|
+
const start = performance.now();
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// -----------------------------------------------------------------------
|
|
32
|
+
// Discover configs from the current workspace
|
|
33
|
+
// -----------------------------------------------------------------------
|
|
34
|
+
const configEntries = await discoverConfigs(debug);
|
|
35
|
+
if (configEntries.length === 0) {
|
|
36
|
+
spinner.stop();
|
|
37
|
+
throw new Error("No Intor config found for type generation.");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// -----------------------------------------------------------------------
|
|
41
|
+
// Collect messages and infer schemas
|
|
42
|
+
// -----------------------------------------------------------------------
|
|
43
|
+
const buildInputs: BuildInput[] = [];
|
|
44
|
+
|
|
45
|
+
// Runtime mode - Per-config processing
|
|
46
|
+
for (const { config, filePath } of configEntries) {
|
|
47
|
+
const { id, supportedLocales } = config;
|
|
48
|
+
printConfigs(id, filePath);
|
|
49
|
+
const messages = await collectRuntimeMessages(
|
|
50
|
+
config,
|
|
51
|
+
config.defaultLocale,
|
|
52
|
+
exts,
|
|
53
|
+
customReaders,
|
|
54
|
+
);
|
|
55
|
+
const schemas = inferSchemas(messages[config.defaultLocale]);
|
|
56
|
+
buildInputs.push({ id, locales: supportedLocales, schemas });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// -----------------------------------------------------------------------
|
|
60
|
+
// Build artifacts and write output
|
|
61
|
+
// -----------------------------------------------------------------------
|
|
62
|
+
const types = buildTypes(buildInputs);
|
|
63
|
+
const schema = buildSchemas(buildInputs);
|
|
64
|
+
|
|
65
|
+
// Write generated files
|
|
66
|
+
const { outDir } = await writeGeneratedFiles({ types, schema });
|
|
67
|
+
|
|
68
|
+
spinner.stop();
|
|
69
|
+
const duration = performance.now() - start;
|
|
70
|
+
printSummary(outDir, duration);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
spinner.stop();
|
|
73
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { generate } from "./generate";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
|
|
3
|
+
export function printSummary(outDir: string, ms: number) {
|
|
4
|
+
const labelWidth = 18;
|
|
5
|
+
const label = (text: string) => pc.dim(text.padEnd(labelWidth));
|
|
6
|
+
|
|
7
|
+
console.log();
|
|
8
|
+
console.log(pc.green(pc.bold("✔ intor generate completed")));
|
|
9
|
+
console.log();
|
|
10
|
+
console.log(label("Output directory: ") + pc.gray(outDir));
|
|
11
|
+
console.log(label("Time elapsed: ") + pc.gray(`${(ms / 1000).toFixed(2)}s`));
|
|
12
|
+
console.log();
|
|
13
|
+
console.log(
|
|
14
|
+
pc.dim("💡 Remember to include ") +
|
|
15
|
+
pc.gray(".intor/**/*.d.ts") +
|
|
16
|
+
pc.dim(" in your tsconfig.json "),
|
|
17
|
+
);
|
|
18
|
+
console.log();
|
|
19
|
+
}
|