@hatchingpoint/point 0.0.6 → 0.0.7
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/LICENSE +21 -21
- package/README.md +34 -34
- package/package.json +34 -30
- package/src/cli.ts +7 -7
- package/src/core/ast.ts +162 -162
- package/src/core/check.ts +412 -412
- package/src/core/cli.ts +497 -497
- package/src/core/context.ts +181 -181
- package/src/core/emit-javascript.ts +124 -124
- package/src/core/emit-typescript.ts +166 -166
- package/src/core/format.ts +6 -6
- package/src/core/incremental.ts +53 -53
- package/src/core/index.ts +12 -12
- package/src/core/lexer.ts +234 -234
- package/src/core/semantic-source.ts +26 -26
- package/src/core/serialize.ts +18 -18
- package/src/core/test-only/core-text-parser.ts +400 -400
- package/src/core/test-only/format-core.ts +120 -120
- package/src/core/test-only/index.ts +3 -3
- package/src/core/test-only/legacy-lowering.ts +1030 -1030
- package/src/index.ts +1 -1
- package/src/semantic/ast.ts +230 -230
- package/src/semantic/callables.ts +51 -51
- package/src/semantic/context.ts +347 -347
- package/src/semantic/desugar.ts +665 -665
- package/src/semantic/expressions.ts +347 -347
- package/src/semantic/format.ts +222 -222
- package/src/semantic/index.ts +10 -10
- package/src/semantic/metadata.ts +37 -37
- package/src/semantic/naming.ts +33 -33
- package/src/semantic/parse.ts +945 -945
- package/src/semantic/serialize.ts +18 -18
|
@@ -1,166 +1,166 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
PointCoreDeclaration,
|
|
3
|
-
PointCoreExpression,
|
|
4
|
-
PointCoreFunctionDeclaration,
|
|
5
|
-
PointCoreParameter,
|
|
6
|
-
PointCorePrimitiveType,
|
|
7
|
-
PointCoreProgram,
|
|
8
|
-
PointCoreStatement,
|
|
9
|
-
PointCoreTypeDeclaration,
|
|
10
|
-
PointCoreTypeExpression,
|
|
11
|
-
PointCoreValueDeclaration,
|
|
12
|
-
} from "./ast.ts";
|
|
13
|
-
|
|
14
|
-
const BINARY_OPERATORS: Record<string, string> = {
|
|
15
|
-
and: "&&",
|
|
16
|
-
or: "||",
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
/** Emit TypeScript from a core AST program. Production path: parsePointSource → check → emit. */
|
|
20
|
-
export function emitPointCoreTypeScript(program: PointCoreProgram): string {
|
|
21
|
-
const lines: string[] = [];
|
|
22
|
-
lines.push("// Generated by Point. Do not edit directly.");
|
|
23
|
-
if (program.module) lines.push(`// Point module: ${program.module}`);
|
|
24
|
-
lines.push("");
|
|
25
|
-
for (const declaration of program.declarations) {
|
|
26
|
-
lines.push(...emitDeclaration(declaration), "");
|
|
27
|
-
}
|
|
28
|
-
return `${trimTrailingBlankLines(lines).join("\n")}\n`;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function emitDeclaration(declaration: PointCoreDeclaration): string[] {
|
|
32
|
-
if (declaration.kind === "import") {
|
|
33
|
-
return [`import { ${declaration.names.join(", ")} } from ${JSON.stringify(declaration.from)};`];
|
|
34
|
-
}
|
|
35
|
-
if (declaration.kind === "external") {
|
|
36
|
-
const imported = declaration.importName ? `${declaration.importName} as ${declaration.name}` : declaration.name;
|
|
37
|
-
return [`import { ${imported} } from ${JSON.stringify(declaration.from)};`];
|
|
38
|
-
}
|
|
39
|
-
if (declaration.kind === "type") return emitType(declaration);
|
|
40
|
-
if (declaration.kind === "value") return [emitValue(declaration, true)];
|
|
41
|
-
return emitFunction(declaration);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function emitType(declaration: PointCoreTypeDeclaration): string[] {
|
|
45
|
-
return [
|
|
46
|
-
`export interface ${declaration.name} {`,
|
|
47
|
-
...declaration.fields.map((field) => ` ${field.name}: ${emitTypeExpression(field.type)};`),
|
|
48
|
-
"}",
|
|
49
|
-
];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function emitFunction(declaration: PointCoreFunctionDeclaration): string[] {
|
|
53
|
-
const asyncPrefix = declaration.semantic?.kind === "action" || declaration.semantic?.kind === "workflow" || declaration.semantic?.kind === "command" ? "async " : "";
|
|
54
|
-
const returnType =
|
|
55
|
-
declaration.semantic?.kind === "action" || declaration.semantic?.kind === "workflow" || declaration.semantic?.kind === "command"
|
|
56
|
-
? `Promise<${emitTypeExpression(declaration.returnType)}>`
|
|
57
|
-
: declaration.semantic?.kind === "view"
|
|
58
|
-
? "JSX.Element"
|
|
59
|
-
: declaration.semantic?.kind === "route"
|
|
60
|
-
? "Response | string"
|
|
61
|
-
: emitTypeExpression(declaration.returnType);
|
|
62
|
-
return [
|
|
63
|
-
`export ${asyncPrefix}function ${declaration.name}(${declaration.params.map(emitParam).join(", ")}): ${returnType} {`,
|
|
64
|
-
...indentLines(declaration.body.flatMap((statement) => emitStatement(statement, declaration.semantic?.kind))),
|
|
65
|
-
"}",
|
|
66
|
-
];
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function emitStatement(statement: PointCoreStatement, semanticKind?: string): string[] {
|
|
70
|
-
if (statement.kind === "return") {
|
|
71
|
-
if (semanticKind === "view" && statement.value?.kind === "literal" && typeof statement.value.value === "string") {
|
|
72
|
-
return [`return <>${escapeJsxText(statement.value.value)}</>;`];
|
|
73
|
-
}
|
|
74
|
-
return [statement.value ? `return ${emitExpression(statement.value)};` : "return;"];
|
|
75
|
-
}
|
|
76
|
-
if (statement.kind === "value") return [emitValue(statement, false)];
|
|
77
|
-
if (statement.kind === "assignment") return [`${statement.name} ${statement.operator} ${emitExpression(statement.value)};`];
|
|
78
|
-
if (statement.kind === "if") {
|
|
79
|
-
const lines = [
|
|
80
|
-
`if (${emitCondition(statement.condition)}) {`,
|
|
81
|
-
...indentLines(statement.thenBody.flatMap((child) => emitStatement(child, semanticKind))),
|
|
82
|
-
"}",
|
|
83
|
-
];
|
|
84
|
-
if (statement.elseBody.length > 0) {
|
|
85
|
-
lines.push(
|
|
86
|
-
"else {",
|
|
87
|
-
...indentLines(statement.elseBody.flatMap((child) => emitStatement(child, semanticKind))),
|
|
88
|
-
"}",
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
return lines;
|
|
92
|
-
}
|
|
93
|
-
if (statement.kind === "for") {
|
|
94
|
-
return [
|
|
95
|
-
`for (const ${statement.itemName} of ${emitExpression(statement.iterable)}) {`,
|
|
96
|
-
...indentLines(statement.body.flatMap((child) => emitStatement(child, semanticKind))),
|
|
97
|
-
"}",
|
|
98
|
-
];
|
|
99
|
-
}
|
|
100
|
-
return [`${emitExpression(statement.value)};`];
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function escapeJsxText(value: string): string {
|
|
104
|
-
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function emitValue(declaration: PointCoreValueDeclaration, exported: boolean): string {
|
|
108
|
-
const prefix = exported ? "export " : "";
|
|
109
|
-
const keyword = declaration.mutable ? "let" : "const";
|
|
110
|
-
return `${prefix}${keyword} ${declaration.name}: ${emitTypeExpression(declaration.type)} = ${emitExpression(declaration.value)};`;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function emitParam(param: PointCoreParameter): string {
|
|
114
|
-
return `${param.name}: ${emitTypeExpression(param.type)}`;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function emitTypeExpression(type: PointCoreTypeExpression): string {
|
|
118
|
-
if (type.name === "List") return `Array<${type.args[0] ? emitTypeExpression(type.args[0]) : "unknown"}>`;
|
|
119
|
-
if (type.name === "Maybe") return `${type.args[0] ? emitTypeExpression(type.args[0]) : "unknown"} | null`;
|
|
120
|
-
if (type.name === "Or") return type.args.map(emitTypeExpression).join(" | ");
|
|
121
|
-
if (type.name === "Error") return "{ message: string }";
|
|
122
|
-
if (isPrimitiveType(type.name)) return emitPrimitiveType(type.name);
|
|
123
|
-
return type.name;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function emitPrimitiveType(type: PointCorePrimitiveType): string {
|
|
127
|
-
if (type === "Text") return "string";
|
|
128
|
-
if (type === "Int" || type === "Float") return "number";
|
|
129
|
-
if (type === "Bool") return "boolean";
|
|
130
|
-
return "void";
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function emitExpression(expression: PointCoreExpression): string {
|
|
134
|
-
if (expression.kind === "literal") return JSON.stringify(expression.value);
|
|
135
|
-
if (expression.kind === "identifier") return expression.name;
|
|
136
|
-
if (expression.kind === "list") return `[${expression.items.map(emitExpression).join(", ")}]`;
|
|
137
|
-
if (expression.kind === "record") {
|
|
138
|
-
return `{ ${expression.fields.map((field) => `${field.name}: ${emitExpression(field.value)}`).join(", ")} }`;
|
|
139
|
-
}
|
|
140
|
-
if (expression.kind === "await") return `await ${emitExpression(expression.value)}`;
|
|
141
|
-
if (expression.kind === "property") return `${emitExpression(expression.target)}.${expression.name}`;
|
|
142
|
-
if (expression.kind === "call") {
|
|
143
|
-
if (expression.callee === "Error") return `{ message: ${expression.args[0] ? emitExpression(expression.args[0]) : JSON.stringify("")} }`;
|
|
144
|
-
return `${expression.callee}(${expression.args.map(emitExpression).join(", ")})`;
|
|
145
|
-
}
|
|
146
|
-
const operator = BINARY_OPERATORS[expression.operator] ?? expression.operator;
|
|
147
|
-
return `(${emitExpression(expression.left)} ${operator} ${emitExpression(expression.right)})`;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function emitCondition(expression: PointCoreExpression): string {
|
|
151
|
-
const emitted = emitExpression(expression);
|
|
152
|
-
return emitted.startsWith("(") && emitted.endsWith(")") ? emitted.slice(1, -1) : emitted;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function isPrimitiveType(type: string): type is PointCorePrimitiveType {
|
|
156
|
-
return type === "Text" || type === "Int" || type === "Float" || type === "Bool" || type === "Void";
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function indentLines(lines: string[]): string[] {
|
|
160
|
-
return lines.map((line) => ` ${line}`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function trimTrailingBlankLines(lines: string[]): string[] {
|
|
164
|
-
while (lines.at(-1) === "") lines.pop();
|
|
165
|
-
return lines;
|
|
166
|
-
}
|
|
1
|
+
import type {
|
|
2
|
+
PointCoreDeclaration,
|
|
3
|
+
PointCoreExpression,
|
|
4
|
+
PointCoreFunctionDeclaration,
|
|
5
|
+
PointCoreParameter,
|
|
6
|
+
PointCorePrimitiveType,
|
|
7
|
+
PointCoreProgram,
|
|
8
|
+
PointCoreStatement,
|
|
9
|
+
PointCoreTypeDeclaration,
|
|
10
|
+
PointCoreTypeExpression,
|
|
11
|
+
PointCoreValueDeclaration,
|
|
12
|
+
} from "./ast.ts";
|
|
13
|
+
|
|
14
|
+
const BINARY_OPERATORS: Record<string, string> = {
|
|
15
|
+
and: "&&",
|
|
16
|
+
or: "||",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** Emit TypeScript from a core AST program. Production path: parsePointSource → check → emit. */
|
|
20
|
+
export function emitPointCoreTypeScript(program: PointCoreProgram): string {
|
|
21
|
+
const lines: string[] = [];
|
|
22
|
+
lines.push("// Generated by Point. Do not edit directly.");
|
|
23
|
+
if (program.module) lines.push(`// Point module: ${program.module}`);
|
|
24
|
+
lines.push("");
|
|
25
|
+
for (const declaration of program.declarations) {
|
|
26
|
+
lines.push(...emitDeclaration(declaration), "");
|
|
27
|
+
}
|
|
28
|
+
return `${trimTrailingBlankLines(lines).join("\n")}\n`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function emitDeclaration(declaration: PointCoreDeclaration): string[] {
|
|
32
|
+
if (declaration.kind === "import") {
|
|
33
|
+
return [`import { ${declaration.names.join(", ")} } from ${JSON.stringify(declaration.from)};`];
|
|
34
|
+
}
|
|
35
|
+
if (declaration.kind === "external") {
|
|
36
|
+
const imported = declaration.importName ? `${declaration.importName} as ${declaration.name}` : declaration.name;
|
|
37
|
+
return [`import { ${imported} } from ${JSON.stringify(declaration.from)};`];
|
|
38
|
+
}
|
|
39
|
+
if (declaration.kind === "type") return emitType(declaration);
|
|
40
|
+
if (declaration.kind === "value") return [emitValue(declaration, true)];
|
|
41
|
+
return emitFunction(declaration);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function emitType(declaration: PointCoreTypeDeclaration): string[] {
|
|
45
|
+
return [
|
|
46
|
+
`export interface ${declaration.name} {`,
|
|
47
|
+
...declaration.fields.map((field) => ` ${field.name}: ${emitTypeExpression(field.type)};`),
|
|
48
|
+
"}",
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function emitFunction(declaration: PointCoreFunctionDeclaration): string[] {
|
|
53
|
+
const asyncPrefix = declaration.semantic?.kind === "action" || declaration.semantic?.kind === "workflow" || declaration.semantic?.kind === "command" ? "async " : "";
|
|
54
|
+
const returnType =
|
|
55
|
+
declaration.semantic?.kind === "action" || declaration.semantic?.kind === "workflow" || declaration.semantic?.kind === "command"
|
|
56
|
+
? `Promise<${emitTypeExpression(declaration.returnType)}>`
|
|
57
|
+
: declaration.semantic?.kind === "view"
|
|
58
|
+
? "JSX.Element"
|
|
59
|
+
: declaration.semantic?.kind === "route"
|
|
60
|
+
? "Response | string"
|
|
61
|
+
: emitTypeExpression(declaration.returnType);
|
|
62
|
+
return [
|
|
63
|
+
`export ${asyncPrefix}function ${declaration.name}(${declaration.params.map(emitParam).join(", ")}): ${returnType} {`,
|
|
64
|
+
...indentLines(declaration.body.flatMap((statement) => emitStatement(statement, declaration.semantic?.kind))),
|
|
65
|
+
"}",
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function emitStatement(statement: PointCoreStatement, semanticKind?: string): string[] {
|
|
70
|
+
if (statement.kind === "return") {
|
|
71
|
+
if (semanticKind === "view" && statement.value?.kind === "literal" && typeof statement.value.value === "string") {
|
|
72
|
+
return [`return <>${escapeJsxText(statement.value.value)}</>;`];
|
|
73
|
+
}
|
|
74
|
+
return [statement.value ? `return ${emitExpression(statement.value)};` : "return;"];
|
|
75
|
+
}
|
|
76
|
+
if (statement.kind === "value") return [emitValue(statement, false)];
|
|
77
|
+
if (statement.kind === "assignment") return [`${statement.name} ${statement.operator} ${emitExpression(statement.value)};`];
|
|
78
|
+
if (statement.kind === "if") {
|
|
79
|
+
const lines = [
|
|
80
|
+
`if (${emitCondition(statement.condition)}) {`,
|
|
81
|
+
...indentLines(statement.thenBody.flatMap((child) => emitStatement(child, semanticKind))),
|
|
82
|
+
"}",
|
|
83
|
+
];
|
|
84
|
+
if (statement.elseBody.length > 0) {
|
|
85
|
+
lines.push(
|
|
86
|
+
"else {",
|
|
87
|
+
...indentLines(statement.elseBody.flatMap((child) => emitStatement(child, semanticKind))),
|
|
88
|
+
"}",
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return lines;
|
|
92
|
+
}
|
|
93
|
+
if (statement.kind === "for") {
|
|
94
|
+
return [
|
|
95
|
+
`for (const ${statement.itemName} of ${emitExpression(statement.iterable)}) {`,
|
|
96
|
+
...indentLines(statement.body.flatMap((child) => emitStatement(child, semanticKind))),
|
|
97
|
+
"}",
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
return [`${emitExpression(statement.value)};`];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function escapeJsxText(value: string): string {
|
|
104
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function emitValue(declaration: PointCoreValueDeclaration, exported: boolean): string {
|
|
108
|
+
const prefix = exported ? "export " : "";
|
|
109
|
+
const keyword = declaration.mutable ? "let" : "const";
|
|
110
|
+
return `${prefix}${keyword} ${declaration.name}: ${emitTypeExpression(declaration.type)} = ${emitExpression(declaration.value)};`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function emitParam(param: PointCoreParameter): string {
|
|
114
|
+
return `${param.name}: ${emitTypeExpression(param.type)}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function emitTypeExpression(type: PointCoreTypeExpression): string {
|
|
118
|
+
if (type.name === "List") return `Array<${type.args[0] ? emitTypeExpression(type.args[0]) : "unknown"}>`;
|
|
119
|
+
if (type.name === "Maybe") return `${type.args[0] ? emitTypeExpression(type.args[0]) : "unknown"} | null`;
|
|
120
|
+
if (type.name === "Or") return type.args.map(emitTypeExpression).join(" | ");
|
|
121
|
+
if (type.name === "Error") return "{ message: string }";
|
|
122
|
+
if (isPrimitiveType(type.name)) return emitPrimitiveType(type.name);
|
|
123
|
+
return type.name;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function emitPrimitiveType(type: PointCorePrimitiveType): string {
|
|
127
|
+
if (type === "Text") return "string";
|
|
128
|
+
if (type === "Int" || type === "Float") return "number";
|
|
129
|
+
if (type === "Bool") return "boolean";
|
|
130
|
+
return "void";
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function emitExpression(expression: PointCoreExpression): string {
|
|
134
|
+
if (expression.kind === "literal") return JSON.stringify(expression.value);
|
|
135
|
+
if (expression.kind === "identifier") return expression.name;
|
|
136
|
+
if (expression.kind === "list") return `[${expression.items.map(emitExpression).join(", ")}]`;
|
|
137
|
+
if (expression.kind === "record") {
|
|
138
|
+
return `{ ${expression.fields.map((field) => `${field.name}: ${emitExpression(field.value)}`).join(", ")} }`;
|
|
139
|
+
}
|
|
140
|
+
if (expression.kind === "await") return `await ${emitExpression(expression.value)}`;
|
|
141
|
+
if (expression.kind === "property") return `${emitExpression(expression.target)}.${expression.name}`;
|
|
142
|
+
if (expression.kind === "call") {
|
|
143
|
+
if (expression.callee === "Error") return `{ message: ${expression.args[0] ? emitExpression(expression.args[0]) : JSON.stringify("")} }`;
|
|
144
|
+
return `${expression.callee}(${expression.args.map(emitExpression).join(", ")})`;
|
|
145
|
+
}
|
|
146
|
+
const operator = BINARY_OPERATORS[expression.operator] ?? expression.operator;
|
|
147
|
+
return `(${emitExpression(expression.left)} ${operator} ${emitExpression(expression.right)})`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function emitCondition(expression: PointCoreExpression): string {
|
|
151
|
+
const emitted = emitExpression(expression);
|
|
152
|
+
return emitted.startsWith("(") && emitted.endsWith(")") ? emitted.slice(1, -1) : emitted;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function isPrimitiveType(type: string): type is PointCorePrimitiveType {
|
|
156
|
+
return type === "Text" || type === "Int" || type === "Float" || type === "Bool" || type === "Void";
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function indentLines(lines: string[]): string[] {
|
|
160
|
+
return lines.map((line) => ` ${line}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function trimTrailingBlankLines(lines: string[]): string[] {
|
|
164
|
+
while (lines.at(-1) === "") lines.pop();
|
|
165
|
+
return lines;
|
|
166
|
+
}
|
package/src/core/format.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { formatSemanticProgram } from "../semantic/format.ts";
|
|
2
|
-
import { parseSemanticSource } from "../semantic/parse.ts";
|
|
3
|
-
|
|
4
|
-
export function formatPointSource(source: string): string {
|
|
5
|
-
return formatSemanticProgram(parseSemanticSource(source));
|
|
6
|
-
}
|
|
1
|
+
import { formatSemanticProgram } from "../semantic/format.ts";
|
|
2
|
+
import { parseSemanticSource } from "../semantic/parse.ts";
|
|
3
|
+
|
|
4
|
+
export function formatPointSource(source: string): string {
|
|
5
|
+
return formatSemanticProgram(parseSemanticSource(source));
|
|
6
|
+
}
|
package/src/core/incremental.ts
CHANGED
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
|
|
4
|
-
const CACHE_DIR = ".point-cache";
|
|
5
|
-
const MANIFEST = "manifest.json";
|
|
6
|
-
|
|
7
|
-
export interface PointBuildCacheEntry {
|
|
8
|
-
sourceHash: string;
|
|
9
|
-
checkedAt: string;
|
|
10
|
-
ok: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface PointBuildCacheManifest {
|
|
14
|
-
schemaVersion: "point.cache.v1";
|
|
15
|
-
entries: Record<string, PointBuildCacheEntry>;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function hashPointSource(source: string): string {
|
|
19
|
-
return createHash("sha256").update(source).digest("hex");
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export async function readBuildCache(cwd = process.cwd()): Promise<PointBuildCacheManifest> {
|
|
23
|
-
const path = resolve(cwd, CACHE_DIR, MANIFEST);
|
|
24
|
-
if (!(await Bun.file(path).exists())) {
|
|
25
|
-
return { schemaVersion: "point.cache.v1", entries: {} };
|
|
26
|
-
}
|
|
27
|
-
return Bun.file(path).json();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export async function writeBuildCache(manifest: PointBuildCacheManifest, cwd = process.cwd()): Promise<void> {
|
|
31
|
-
const path = resolve(cwd, CACHE_DIR, MANIFEST);
|
|
32
|
-
await Bun.$`mkdir -p ${resolve(cwd, CACHE_DIR)}`.quiet();
|
|
33
|
-
await Bun.write(path, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function isIncrementalEnabled(): boolean {
|
|
37
|
-
return process.env.POINT_INCREMENTAL === "1" || process.env.POINT_INCREMENTAL === "true";
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function isCacheHit(manifest: PointBuildCacheManifest, input: string, source: string): boolean {
|
|
41
|
-
const entry = manifest.entries[input];
|
|
42
|
-
return Boolean(entry && entry.sourceHash === hashPointSource(source) && entry.ok);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function recordCacheEntry(manifest: PointBuildCacheManifest, input: string, source: string, ok: boolean): PointBuildCacheManifest {
|
|
46
|
-
return {
|
|
47
|
-
...manifest,
|
|
48
|
-
entries: {
|
|
49
|
-
...manifest.entries,
|
|
50
|
-
[input]: { sourceHash: hashPointSource(source), checkedAt: new Date().toISOString(), ok },
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
}
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
const CACHE_DIR = ".point-cache";
|
|
5
|
+
const MANIFEST = "manifest.json";
|
|
6
|
+
|
|
7
|
+
export interface PointBuildCacheEntry {
|
|
8
|
+
sourceHash: string;
|
|
9
|
+
checkedAt: string;
|
|
10
|
+
ok: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface PointBuildCacheManifest {
|
|
14
|
+
schemaVersion: "point.cache.v1";
|
|
15
|
+
entries: Record<string, PointBuildCacheEntry>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function hashPointSource(source: string): string {
|
|
19
|
+
return createHash("sha256").update(source).digest("hex");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function readBuildCache(cwd = process.cwd()): Promise<PointBuildCacheManifest> {
|
|
23
|
+
const path = resolve(cwd, CACHE_DIR, MANIFEST);
|
|
24
|
+
if (!(await Bun.file(path).exists())) {
|
|
25
|
+
return { schemaVersion: "point.cache.v1", entries: {} };
|
|
26
|
+
}
|
|
27
|
+
return Bun.file(path).json();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function writeBuildCache(manifest: PointBuildCacheManifest, cwd = process.cwd()): Promise<void> {
|
|
31
|
+
const path = resolve(cwd, CACHE_DIR, MANIFEST);
|
|
32
|
+
await Bun.$`mkdir -p ${resolve(cwd, CACHE_DIR)}`.quiet();
|
|
33
|
+
await Bun.write(path, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function isIncrementalEnabled(): boolean {
|
|
37
|
+
return process.env.POINT_INCREMENTAL === "1" || process.env.POINT_INCREMENTAL === "true";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function isCacheHit(manifest: PointBuildCacheManifest, input: string, source: string): boolean {
|
|
41
|
+
const entry = manifest.entries[input];
|
|
42
|
+
return Boolean(entry && entry.sourceHash === hashPointSource(source) && entry.ok);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function recordCacheEntry(manifest: PointBuildCacheManifest, input: string, source: string, ok: boolean): PointBuildCacheManifest {
|
|
46
|
+
return {
|
|
47
|
+
...manifest,
|
|
48
|
+
entries: {
|
|
49
|
+
...manifest.entries,
|
|
50
|
+
[input]: { sourceHash: hashPointSource(source), checkedAt: new Date().toISOString(), ok },
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
package/src/core/index.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export * from "./ast.ts";
|
|
2
|
-
export * from "./check.ts";
|
|
3
|
-
export { findRunEntryName } from "./cli.ts";
|
|
4
|
-
export * from "./context.ts";
|
|
5
|
-
export * from "./emit-typescript.ts";
|
|
6
|
-
export * from "./emit-javascript.ts";
|
|
7
|
-
export * from "./incremental.ts";
|
|
8
|
-
export * from "./serialize.ts";
|
|
9
|
-
export * from "../semantic/index.ts";
|
|
10
|
-
export * from "./format.ts";
|
|
11
|
-
export * from "./lexer.ts";
|
|
12
|
-
export * from "./parser.ts";
|
|
1
|
+
export * from "./ast.ts";
|
|
2
|
+
export * from "./check.ts";
|
|
3
|
+
export { findRunEntryName } from "./cli.ts";
|
|
4
|
+
export * from "./context.ts";
|
|
5
|
+
export * from "./emit-typescript.ts";
|
|
6
|
+
export * from "./emit-javascript.ts";
|
|
7
|
+
export * from "./incremental.ts";
|
|
8
|
+
export * from "./serialize.ts";
|
|
9
|
+
export * from "../semantic/index.ts";
|
|
10
|
+
export * from "./format.ts";
|
|
11
|
+
export * from "./lexer.ts";
|
|
12
|
+
export * from "./parser.ts";
|