-
Notifications
You must be signed in to change notification settings - Fork 101
Add a script which can import a .shortcut file and generate JS from it #4
Comments
How should the .js file be generated? Should this library/module be able to convert .shortcut to .js without data loss (i.e. having the obtained .js file to build exactly - except for magic variables UUIDs - the same imported .shortcut file)? |
Yes, that's what I'm envisaging. As you said; in an ideal world you'd be able to take a .shortcut, convert it to JS, then back to a .shortcut. The two .shortcut files should be completely identical. |
Magic variables With @Archez's pull request, output variables and "proper variables" (the ones you define with setVariable) can be placed in JS template strings and a A solution could be to have JS objects instead of strings and to pass those objects to let outputVariable = {
uuid: 'b74c81a8-192a-463f-a0a6-2d327963714f',
name: 'Division Result',
type: 'ActionOutput'
}
let properVariable = {
name: 'Test Name',
type: 'Variable'
}
let clipboardGlobalVariable = { type: 'Clipboard' }
let askGlobalVariable = { type: 'Ask' }
let currentDateGlobalVariable = { type: 'CurrentDate' }
let extensionInputGlobalVariable = { type: 'ExtensionInput' } let calcId
const actions = [
number({
number: 42
}),
calculate({
operand: 3,
operation: '/'
}, (id) => {
return calcId = { uuid: id, name: 'Division Result', type: 'ActionOutput' }
})
] What is your opinion? |
I'm currently looking into defining serialized constants for the global variables. These constants would bypass the string check, and allow them to be used directly. I agree with @xAlien95 suggestion as far as attempting to set the EDIT: Yes, the original action that gets a renamed magic variable has a |
My suggestion is to remove the UUID creation in const actionOutput = name => ({ uuid: uuidv4(), name: name, type: 'ActionOutput' }) export const withActionOutput = <OptionsType>(
actionBuilder: (options: OptionsType) => WFWorkflowAction,
) => (
(
options: OptionsType,
actionOutput?: ActionOutput,
): WFWorkflowAction => {
const action = actionBuilder(options);
// If we've got an action output
if (actionOutput) {
action.WFWorkflowActionParameters.UUID = actionOutput.uuid;
if (actionOutput.name) action.WFWorkflowActionParameters.CustomOutputName = actionOutput.name;
}
return action;
}
); This is currently the best approach I can think of, which results in a slightly different way to write the code. Before you had: let calcId
const actions = [
number({
number: 42
}),
calculate({
operand: 3,
operation: '/'
}, (id) => {
calcId = id
})
] While now you have: let calcId = actionOutput('Division Result')
const actions = [
number({
number: 42
}),
calculate({
operand: 3,
operation: '/'
}, calcId)
] In this way the user has to define (and create) the action output before its use in the actionBuilder. |
@joshfarrant, do you want to start working on the parser on your own? I didn't wrote anything exhaustive, but I have a few features that the parser should have:
Something on this line: const buildScript = (
shortcut: WFWorkflow,
): Script => {
...
}; interface Script {
metadata: {
glyph?: number;
color?: number;
};
variables: {
name: string; // the variable name in the built .js file
variableName: string;
}[];
actionOutputs: {
name: string; // the variable name in the built .js file
outputName?: string;
}[];
actions: Action[];
// a list to keep track of all the functions to be imported from the npm module
imports: { [submodule: string]: string[] };
} This way, a .js file can be built from the |
I've been making some progress on this over the last few days. Currently, the process looks something like this: const {
buildScript,
} = require('../build');
(async () => {
const script = await buildScript('shortcuts/Playground.shortcut');
console.log(script);
})(); Outputs: {
"imports": {
"actions": [
"calculate"
]
},
"metadata": {
"glyph": "E96C",
"color": "GRAY"
},
"actions": [
{
"name": "calculate",
"options": {
"scientificOperation": "x^y",
"operand": 7
}
},
{
"name": "calculate",
"options": {
"operation": "+",
"operand": 42
}
},
{
"name": "calculate",
"options": {
"scientificOperation": "∛x",
"operand": 7
}
}
]
} This It will require a few modifications to all existing actions:
For example, these modifications would convert the the import WFWorkflowAction from '../interfaces/WF/WFWorkflowAction';
interface Options {
/** The body of the comment */
text?: string;
}
export const identifier = 'is.workflow.actions.comment';
/**
* @action Comment
* @section Actions > Scripting >
* @icon Text
*
* This action lets you explain how part of a shortcut works. When run, this action does nothing.
*
* ```js
* // Create a comment
* comment({
* text: 'A very important comment',
* });
* ```
*/
const comment = (
{
text = '',
}: Options,
): WFWorkflowAction => ({
WFWorkflowActionIdentifier: identifier,
WFWorkflowActionParameters: {
WFCommentActionText: text,
},
});
export const invert = (
WFAction: WFWorkflowAction,
): Options => ({
text: WFAction.WFWorkflowActionParameters.WFCommentActionText,
});
export default comment; That's it, for the time being. The implementation may well change before it's released, but I just wanted to share a bit of info on how it's all looking. I'll publish my branch in it's current state later on today. |
@joshfarrant, it's better to place TypeDoc comments on default values: import WFWorkflowAction from '../interfaces/WF/WFWorkflowAction';
interface Options {
text?: string;
}
const identifier = 'is.workflow.actions.comment';
/**
* @action Comment
* @section Actions > Scripting >
* @icon Text
*
* This action lets you explain how part of a shortcut works. When run, this action does nothing.
*
* ```js
* // Create a comment
* comment({
* text: 'A very important comment',
* });
* ```
*/
const comment = (
{
/** The body of the comment */
text = '',
}: Options,
): WFWorkflowAction => ({
WFWorkflowActionIdentifier: identifier,
WFWorkflowActionParameters: {
WFCommentActionText: text,
},
});
const invert = (
WFAction: WFWorkflowAction,
): Options => ({
text: WFAction.WFWorkflowActionParameters.WFCommentActionText,
});
export {
comment as default,
invert,
identifier,
}; This is the only way to get default values from TypeDoc. Correct value types can be extracted from the |
👌 |
I’ve pushed to the script-generator branch with my changes so far. As I said, this is far from done and I’m open to feedback/questions on any decisions. Sent with GitHawk |
This could be an amazing feature! I'd love to see this in action as I think both JavaScript and Apple's editor are amazing tools, each with their own advantages. I think it's a lot easier to code large JSON objects and a lot easier to search + drag and drop to find the exact action you need. I'd love to be able to convert from shortcut to js and back easily! Is there any update for merging this branch? I feel it has gone a little stale:
I also have some other ideas, maybe I should create new issues for them, let me know all your thoughts:
|
It could be useful to essentially do the reverse of what Shortcuts-js currently does, and generate JavaScript from an imported .shortcut file.
This could be useful to help people get started with the library and start modifying their existing Shortcuts.
We'd have to find a way to add a placeholder (maybe a comment action?) if a specific action isn't yet implemented in Shortcuts-js.
The text was updated successfully, but these errors were encountered: